Linux中I/O库函数(自学笔记)
一.I/O库概述
1.I/O库
库函数,其实就是将已写好的函数放到一个库中,供人们使用;
I/O库函数,其实就是负责输入(input)及输出(output)的一类函数组成的库。
方法是把一些常用到的函数编完放到一个文件里,供不同的人进行调用。调用的时候把它所在的文件名用#include<>加到里面就可以了。一般是放到lib文件里的。不受平台限制。
2.流
流是I/O库中一个比较重要的概念,对于标准I/O库,它们的操作都是围绕流进行的:
对于标准的C函数库,文件操作都是围绕着流来进行的,流是一个抽象的概念,当程序需要读取数据的时候,开启一个通向数据源的流,数据源可以是文件,内存,网络连接等;当程序需要写入数据时,开启一个通向目的地的流,如下图:
所以,当用标准I/O库打开或创建一个文件时,我们以使一个流与一个文件相关联。
当打开一个流时(使用fopen函数),标准IO函数fopen返回一个指向FILE对象的指针。该对象通常是一个结构,它包含标准IO库为管理该流所需要的所有信息,包括用于实际IO的文件描述符、指向该流缓冲区的指针、缓冲区的长度、当前缓冲区中的字符数以及出错标志等。
为了引用一个流,需要将FILE 指针作为参数传递给每个标准IO函数。我们称指向FILE对象的指针为文件指针。(FILE*)
一般在代码中使用格式 FILE *fp。
3.系统调用
定义: 应用程序通过系统调用请求操作系统的服务。
系统中各种共享资源都由操作系统统一掌握,因此在用户程序中,凡是与资源有关的操作,都必须通过系统调用的方式向操作系统提出服务请求,由操作系统代为完成,这样可以保证系统的稳定性和安全性,防止用户进行非法操作。
即:各种应用程序各种请求都是面向OS的,而相应的操作,由OS控制硬件完成。
二.I/O库算法(参考链接:https://blog.csdn.net/weixin_52042488/article/details/125743762)
1.fopen —— fclose
fopen函数
FILE *fopen(const char *path,const char *mode);
返回值:struct_IO_FILE, 在/usr/include/libio.h可以查看其定义
这个结构体包含有:读写缓存的首地址,大小,位置指针等。
那么对于特殊的“文件”,路径有如下:
标准的输入流 stdin 0
标准的输出流 stdout 1
标准的出错流 stderr 2
fclose函数
调用成功返回0,失败返回EOF,并且设置errno
在该文件被关闭之前,刷新缓存中的数据。如果标准I/O库已经为该流自动分配了一个缓存,则释放此缓存。
2.fputs —— fgets
fputs函数
char fgets(char s,int size,FILE *stream)
第一个参数:缓存,即读到那里去
第二个参数:读多少字节
第三个参数:从什么地方读
返回值:若成功则为s(缓存的地址),若已处文件尾端或者出错则为NULL
fgets函数
int fputs(const char* s,FILE *stream)
第一个参数:缓存,即写什么内容
第二个参数:写到哪里去
返回值:若成功则为非负值,若出错则为EOF(一个宏定义,值为-1 )
3.fread —— fwrite
size_t fread(void* ptr,size_t size,size_t nmemb,FILE* fp);
size_t fwrite(const void ptr,size_t size,size_t nmemb,FILE fp);
功能:全缓存的读写函数
第一个参数(char*)ptr:读的存放点/写的内容
第二个参数:(size_t)size:每个读写单元内容的字节数
第三个参数:(size_t)nmemb:读写内容有多少个单元
第四个参数:(FILE*)fp:读写文件流
三.I/O库模式
1.字符模式
实例:Linux系统中按字符复制文件
命令:emacs mycs.c //打开空白文档
代码作用:将原文件内容按字符复制到新文件中
源代码:
1 #include <stdio.h>
2 int main(int argc , char *argv[] )
3 {
4 FILE *fps , *fpd;
5 int ch;
6 if(argc <3)
7 {
8 printf("Usage : %s <src_file> <dst_file>\n",argv[0]);//如编译格式不对报错
9 return -1;
10 }
11 if ((fps=fopen(argv[1],"r"))==NULL)
12 {
13 perror("fopen src file");//如不存在原文件as报错
14 return -1;
15 }
16 if ((fpd=fopen(argv[2],"r"))==NULL)
17 {
18 perror("fopen dst file");//如不存在原文件as报错
19 return -1;
20 }
21 while((ch = fgetc(fps))!=EOF)
22 {
23 fputc(ch,fpd);//从原文件中取字符,输入到新文件中
24 }
25 fclose(fps);
26 fclose(fpd);
27 return 0;
28 }//yaoyu-er
编译及验证环节:
2.行模式
char *fgets(char *buf, int size, FILE *fp):从fp中读取最多为一行(以\n为结尾)的字符。
int fputs(char *buf, FILE *fp):将buf中的一行写入fp中。
四.文件流缓冲(参考链接:https://blog.csdn.net/superSmart_Dong/article/details/120681145)
每个文件流都包含有一个FILE 结构体,其中包含一个内部缓冲区。由于文件是存储在磁盘中。频繁的写磁盘耗时耗资源。通常把内容放在内存中,再把该内存中的数据一次性写入文件。缓冲方案有三种
1)无缓冲 _IONBUF:每次读取的字符尽快地传输到文件或者从文件中传出,例如stderr
2) 行缓冲 _IOLBUF:每次读取的字符写入到缓冲区中,读取到换行符时,再将缓冲区的内容传输/传出到文件,例如 stdout
3) 全缓冲 _IOFBUF:把全部读取的字符都写入到缓冲区,再一次性传输/传出到文件。例如文件流 。
1 #include <stdio.h> 2 3 int main(){ 4 //setvbuf(stdout,NULL,_IONBUF,0); 5 int i=10; 6 while(i--){ 7 printf("hi "); 8 // fflush(stdout); 9 sleep(1); 10 } 11 }
上面的案例直到程序执行完都不会看见输出的信息。因为stdout是行缓冲的,而循环体中都没遇见换行符。如果打开 setvbuf 注释,把stdout设置为无缓冲,那么输出的信息是每个字符每个字符地出现。如果打开 fflush 注释,把stdout的缓冲区清除,那么缓冲区内的信息再清除时都会被输出出来。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!