介绍标准 I/O 是 C 标准库提供的文件操作接口它封装了底层系统调用并引入了用户态缓冲区机制。掌握标准 I/O 后开发者便能在任何支持 C 语言的环境中以统一、可移植的方式对文件进行读写操作极大地提升了开发效率和代码的跨平台性。2.标准IO函数介绍1.fopen函数--打开文件#include stdio.h FILE *fopen(const char *pathname, const char *mode);返回值返回值含义FILE *成功返回一个指向FILE结构体的指针文件流指针用于后续所有文件操作NULL失败可以通过perror()或errno查看具体错误原因参数pathname解释需要打开的路径参数mode解释选择打开文件的模式模式含义文件不存在文件存在初始位置可读可写r只读❌ 失败返回 NULL打开文件开头✅❌r读写❌ 失败返回 NULL打开文件开头✅✅w只写✅ 新建⚠️ 清空截断为 0文件开头❌✅w读写✅ 新建⚠️ 清空截断为 0文件开头✅✅a追加只写✅ 新建打开写入位置在末尾文件末尾❌✅a追加读写✅ 新建打开写入位置在末尾文件末尾✅✅2.fread函数--读文件#include stdio.h size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);返回值解释返回读取到的数据个数当size设置为1时返回值含义 nmemb成功读取了nmemb个完整元素全部读满 nmemb读取的元素个数少于预期可能遇到文件末尾EOF或出错注意返回值跟nmemb有关参数size解释需要读取的字符块的大小参数nmemb解释需要读取的字符块个数读取的数据个数为size * nmembe.gfread(buf, 2, 10, fp) ---读取10个字节块每个字节块有2个字节参数 stream解释文件流指针通过fopen的返回值得到3.fwrite函数--写文件#include stdio.h size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);返回值返回值含义 nmemb成功所有数据块都完整写入 nmemb写入出错如磁盘满、文件权限问题返回值是实际完整写入的数据块数量注意返回值跟nmemb有关参数ptr解释写入的数据来源参数size解释你要写入的字节块大小参数nmemb解释你要写入的字节块个数写入的数据个数为size * nmembe.gfwrite(buf, 2, 10, fp) ---写入10个字节块每个字节块有2个字节与fread很相似参数stream解释文件流指针4.fclose函数--关闭文件#include stdio.h int fclose(FILE *stream)解释关闭文件5.feof函数--判断光标是否到达末尾#include stdio.h int feof(FILE *stream);返回值判断光标是否到文件末尾返回值含义0假尚未到达文件末尾非0真已经到达文件末尾注意是“已经”不是“将要”6.fseek函数--光标偏移int fseek(FILE *stream, long offset, int whence)返回值偏移成功--0偏移失败---1参数 stream文件流指针offset 偏移量whence需要从哪里开始偏移SEEK_SET从文本头开始SEEK_CUR当前位置开始SEEK_CUR从文本末尾开始注意1、使用偏移是不要让偏移量越过文件头比如fseek(fp, -1, SEEK_SET),这样的话这次的移动操作无效光标还是在原本的位置2、偏移量超过文件尾部会导致超出的范围以NULL填充比如fseek(fp,10,SEEK_END),文本末尾超出10个这10个位置会被NULL填充7.ftell函数--读取当前光标到文件头的距离int ftell(FILE *stream);返回值成功运行返回光标当前位置到文件头的字节数参数stream文件流指针可以用ftell得到文本的长度fseekfp 0 SEEK_ENDint length ftell(fp);8.fgets函数--按行读取文件一次最多读取一行char *fgets(char *s, int size, FILE *stream);返回值成功返回读取到的一行数据的首地址失败NULL参数s读出后存放数据的指针size需要读取多少个数据stream文件流指针注意如果size当行的数据个数也只会读取完当行的数据不会到下一行int main(void) { FILE *fp; fp fopen(demo.txt, r); char rd_buf[20] {0}; char wr_buf[20] yueqian; if(fp NULL) { perror(错误); return -1; } char *data fgets(rd_buf, 10, fp); //打印读取的数据 printf(rd_buf读出的数据:%s\n,rd_buf); printf(data的数据:%s\n,data); fclose(fp); return 0; }运行结果如下9.fputs函数--一次向文件中写入一个字符串int fputc(int c, FILE *stream);返回值成功0(写入的字符个数)失败-1参数s需要写入的字符串stream文件流指针int main(void) { FILE *fp; fp fopen(demo.txt, a); char rd_buf[20] {0}; char wr_buf[20] 你好; if(fp NULL) { perror(错误); return -1; } fputs(wr_buf, fp); fclose(fp); return 0; }10.fgetc函数--从文本中读取一个字符int fgetc(FILE *stream);返回值成功返回该字符的ASCII码值失败-1参数stream文件流指针int main(void) { FILE *fp; fp fopen(demo.txt, a); char rd_buf[20] {0}; char wr_buf[20] 你好; if(fp NULL) { perror(错误); return -1; } char data fgetc(fp); printf(%c\n, data); fclose(fp); return 0; }运行结果文本内数据为hello11.fputc--每次向文本内写入一个字节int fputc(int c, FILE *stream);返回值成功返回该字符的ASCII码值失败-1参数stream文件流指针int main(void) { FILE *fp; fp fopen(demo.txt, a); char rd_buf[20] {0}; char wr_buf[20] 你好; if(fp NULL) { perror(错误); return -1; } int data fputc(a, fp); printf(向文件中写入了%c\n, data); fclose(fp); return 0; }运行结果12.fprintf函数--按照指定格式把数据合并写入到stream代表的文件中int fprintf(FILE *stream, const char *format,...);返回值成功返回写入文本的字符个数不包含\0失败-1参数stream文件流指针format可变参数举例int main(void) { FILE *fp; fp fopen(demo.txt, a); char rd_buf[20] {0}; char wr_buf[20] 你好; int data1 666; char data2[20] 新年快乐; if(fp NULL) { perror(错误); return -1; } fprintf(fp, %d%s, data1, data2); fclose(fp); return 0; }对比3者printf --格式化输出函数sprintf --格式化内容然后存在数组中fprintf --格式化内容然后写入文件中13.fscanf--按照指定格式把数据从文件里面出去出来然后拆分到各个变量中int fprintf(FILE *stream, const char *format,...);返回值成功返回读出文本的字符个数不包含\0失败-1参数stream文件流指针format可变参数举例int main(void) { FILE *fp; fp fopen(demo.txt, a); char rd_buf[20] {0}; char wr_buf[20] 你好; char name[50] {0}; char pwd[50] {0}; int y 0, m 0, d 0; if(fp NULL) { perror(错误); return -1; } fscanf(fp, %[^]%[^\n]\n, name, pwd); printf(用户名:%s\t密码%s\n, name, pwd); fscanf(fp, %[^]%[^\n]\n, name, pwd); printf(用户名:%s\t密码%s\n, name, pwd); fscanf(fp, %[^]%[^\n]\n, name, pwd); printf(用户名:%s\t密码%s\n, name, pwd); fclose(fp); return 0; }运行结果文本内数据对比3者scanf --从屏幕中读取输入的数据sscanf --从数组中读取指定格式的数据并拆分到各个变量中fscanf --从文件中读取数据然后根据指定格式拆分数据到各个变量中14.fflush函数--刷新缓冲区int fflush(FILE *stream)返回值成功0失败-1并设置错误信息参数stream指定需要刷新缓存的文件为什么要刷新缓冲区标准IO存在缓冲机制在向文件写入数据时会先将数据存在缓冲区等到一定条件才将缓冲区内的数据写入文件缓冲区更新的条件:1.缓冲区满了自动刷新2.缓冲区没有满主函数return退出的时候会刷新3.fclose()关闭文件时刷新4.主动调用函数fflush刷新缓冲区举例int main(void) { FILE *fp; fp fopen(demo.txt, a); if(fp NULL) { perror(错误); return -1; } while(1) { fwrite(hello, sizeof(char), strlen(hello), fp); sleep(1); //fflush(fp); } fclose(fp); return 0; }如果不在while中加入fflush手动刷新缓冲区那么fwrite要写入的数据就需要等到缓冲区满了之后才会写入文件加入了fflush每次写入都会反馈到文件中3.标准IO与系统IO的差别博主也总结了一份系统IO的笔记有兴趣也可以看看这份Linux系统IO-CSDN博客1.操作符号不同系统IO通过文件描述符来表示文件标准IO通过文件流指针来表示文件2.出身不同系统IO是Linux环境下操作系统提供的文件操作方式标准IO是在系统IO的基础上做了二次封装加入了缓冲区3.性能开销系统IO偏慢--每次读写操作都是通过使用CPU进行操作会增加CPU的消耗标准IO较快--在进行操作时会将数据先填入缓冲区等到一定条件时会一次性写入文件里面减少了CPU的操作次数4.可移植性系统IO--不可移植只能在Linux中使用标准IO--可移植性强因为是属于C语言标准库中的函数只要能够使用C语言的情况下都是可以使用的4.标准IO和系统IO的应用场景标准IO的使用场景读写文本记事本、word文档、二进制文件音频、视频理由标准IO的缓冲区机制能够提高对于文本的快速操作系统IO的使用场景用于操作硬件设备的驱动文件、网络通信理由一般这类文件都是由操作系统提供的接口使用系统IO能够减少接口之间不同导致的问题对于这类文件一般都需要实时性如果使用标准IO,由于存在缓冲区不能在调用fread后立马写入到设备文件中出现滞后的现象
标准IO学习
介绍标准 I/O 是 C 标准库提供的文件操作接口它封装了底层系统调用并引入了用户态缓冲区机制。掌握标准 I/O 后开发者便能在任何支持 C 语言的环境中以统一、可移植的方式对文件进行读写操作极大地提升了开发效率和代码的跨平台性。2.标准IO函数介绍1.fopen函数--打开文件#include stdio.h FILE *fopen(const char *pathname, const char *mode);返回值返回值含义FILE *成功返回一个指向FILE结构体的指针文件流指针用于后续所有文件操作NULL失败可以通过perror()或errno查看具体错误原因参数pathname解释需要打开的路径参数mode解释选择打开文件的模式模式含义文件不存在文件存在初始位置可读可写r只读❌ 失败返回 NULL打开文件开头✅❌r读写❌ 失败返回 NULL打开文件开头✅✅w只写✅ 新建⚠️ 清空截断为 0文件开头❌✅w读写✅ 新建⚠️ 清空截断为 0文件开头✅✅a追加只写✅ 新建打开写入位置在末尾文件末尾❌✅a追加读写✅ 新建打开写入位置在末尾文件末尾✅✅2.fread函数--读文件#include stdio.h size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);返回值解释返回读取到的数据个数当size设置为1时返回值含义 nmemb成功读取了nmemb个完整元素全部读满 nmemb读取的元素个数少于预期可能遇到文件末尾EOF或出错注意返回值跟nmemb有关参数size解释需要读取的字符块的大小参数nmemb解释需要读取的字符块个数读取的数据个数为size * nmembe.gfread(buf, 2, 10, fp) ---读取10个字节块每个字节块有2个字节参数 stream解释文件流指针通过fopen的返回值得到3.fwrite函数--写文件#include stdio.h size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);返回值返回值含义 nmemb成功所有数据块都完整写入 nmemb写入出错如磁盘满、文件权限问题返回值是实际完整写入的数据块数量注意返回值跟nmemb有关参数ptr解释写入的数据来源参数size解释你要写入的字节块大小参数nmemb解释你要写入的字节块个数写入的数据个数为size * nmembe.gfwrite(buf, 2, 10, fp) ---写入10个字节块每个字节块有2个字节与fread很相似参数stream解释文件流指针4.fclose函数--关闭文件#include stdio.h int fclose(FILE *stream)解释关闭文件5.feof函数--判断光标是否到达末尾#include stdio.h int feof(FILE *stream);返回值判断光标是否到文件末尾返回值含义0假尚未到达文件末尾非0真已经到达文件末尾注意是“已经”不是“将要”6.fseek函数--光标偏移int fseek(FILE *stream, long offset, int whence)返回值偏移成功--0偏移失败---1参数 stream文件流指针offset 偏移量whence需要从哪里开始偏移SEEK_SET从文本头开始SEEK_CUR当前位置开始SEEK_CUR从文本末尾开始注意1、使用偏移是不要让偏移量越过文件头比如fseek(fp, -1, SEEK_SET),这样的话这次的移动操作无效光标还是在原本的位置2、偏移量超过文件尾部会导致超出的范围以NULL填充比如fseek(fp,10,SEEK_END),文本末尾超出10个这10个位置会被NULL填充7.ftell函数--读取当前光标到文件头的距离int ftell(FILE *stream);返回值成功运行返回光标当前位置到文件头的字节数参数stream文件流指针可以用ftell得到文本的长度fseekfp 0 SEEK_ENDint length ftell(fp);8.fgets函数--按行读取文件一次最多读取一行char *fgets(char *s, int size, FILE *stream);返回值成功返回读取到的一行数据的首地址失败NULL参数s读出后存放数据的指针size需要读取多少个数据stream文件流指针注意如果size当行的数据个数也只会读取完当行的数据不会到下一行int main(void) { FILE *fp; fp fopen(demo.txt, r); char rd_buf[20] {0}; char wr_buf[20] yueqian; if(fp NULL) { perror(错误); return -1; } char *data fgets(rd_buf, 10, fp); //打印读取的数据 printf(rd_buf读出的数据:%s\n,rd_buf); printf(data的数据:%s\n,data); fclose(fp); return 0; }运行结果如下9.fputs函数--一次向文件中写入一个字符串int fputc(int c, FILE *stream);返回值成功0(写入的字符个数)失败-1参数s需要写入的字符串stream文件流指针int main(void) { FILE *fp; fp fopen(demo.txt, a); char rd_buf[20] {0}; char wr_buf[20] 你好; if(fp NULL) { perror(错误); return -1; } fputs(wr_buf, fp); fclose(fp); return 0; }10.fgetc函数--从文本中读取一个字符int fgetc(FILE *stream);返回值成功返回该字符的ASCII码值失败-1参数stream文件流指针int main(void) { FILE *fp; fp fopen(demo.txt, a); char rd_buf[20] {0}; char wr_buf[20] 你好; if(fp NULL) { perror(错误); return -1; } char data fgetc(fp); printf(%c\n, data); fclose(fp); return 0; }运行结果文本内数据为hello11.fputc--每次向文本内写入一个字节int fputc(int c, FILE *stream);返回值成功返回该字符的ASCII码值失败-1参数stream文件流指针int main(void) { FILE *fp; fp fopen(demo.txt, a); char rd_buf[20] {0}; char wr_buf[20] 你好; if(fp NULL) { perror(错误); return -1; } int data fputc(a, fp); printf(向文件中写入了%c\n, data); fclose(fp); return 0; }运行结果12.fprintf函数--按照指定格式把数据合并写入到stream代表的文件中int fprintf(FILE *stream, const char *format,...);返回值成功返回写入文本的字符个数不包含\0失败-1参数stream文件流指针format可变参数举例int main(void) { FILE *fp; fp fopen(demo.txt, a); char rd_buf[20] {0}; char wr_buf[20] 你好; int data1 666; char data2[20] 新年快乐; if(fp NULL) { perror(错误); return -1; } fprintf(fp, %d%s, data1, data2); fclose(fp); return 0; }对比3者printf --格式化输出函数sprintf --格式化内容然后存在数组中fprintf --格式化内容然后写入文件中13.fscanf--按照指定格式把数据从文件里面出去出来然后拆分到各个变量中int fprintf(FILE *stream, const char *format,...);返回值成功返回读出文本的字符个数不包含\0失败-1参数stream文件流指针format可变参数举例int main(void) { FILE *fp; fp fopen(demo.txt, a); char rd_buf[20] {0}; char wr_buf[20] 你好; char name[50] {0}; char pwd[50] {0}; int y 0, m 0, d 0; if(fp NULL) { perror(错误); return -1; } fscanf(fp, %[^]%[^\n]\n, name, pwd); printf(用户名:%s\t密码%s\n, name, pwd); fscanf(fp, %[^]%[^\n]\n, name, pwd); printf(用户名:%s\t密码%s\n, name, pwd); fscanf(fp, %[^]%[^\n]\n, name, pwd); printf(用户名:%s\t密码%s\n, name, pwd); fclose(fp); return 0; }运行结果文本内数据对比3者scanf --从屏幕中读取输入的数据sscanf --从数组中读取指定格式的数据并拆分到各个变量中fscanf --从文件中读取数据然后根据指定格式拆分数据到各个变量中14.fflush函数--刷新缓冲区int fflush(FILE *stream)返回值成功0失败-1并设置错误信息参数stream指定需要刷新缓存的文件为什么要刷新缓冲区标准IO存在缓冲机制在向文件写入数据时会先将数据存在缓冲区等到一定条件才将缓冲区内的数据写入文件缓冲区更新的条件:1.缓冲区满了自动刷新2.缓冲区没有满主函数return退出的时候会刷新3.fclose()关闭文件时刷新4.主动调用函数fflush刷新缓冲区举例int main(void) { FILE *fp; fp fopen(demo.txt, a); if(fp NULL) { perror(错误); return -1; } while(1) { fwrite(hello, sizeof(char), strlen(hello), fp); sleep(1); //fflush(fp); } fclose(fp); return 0; }如果不在while中加入fflush手动刷新缓冲区那么fwrite要写入的数据就需要等到缓冲区满了之后才会写入文件加入了fflush每次写入都会反馈到文件中3.标准IO与系统IO的差别博主也总结了一份系统IO的笔记有兴趣也可以看看这份Linux系统IO-CSDN博客1.操作符号不同系统IO通过文件描述符来表示文件标准IO通过文件流指针来表示文件2.出身不同系统IO是Linux环境下操作系统提供的文件操作方式标准IO是在系统IO的基础上做了二次封装加入了缓冲区3.性能开销系统IO偏慢--每次读写操作都是通过使用CPU进行操作会增加CPU的消耗标准IO较快--在进行操作时会将数据先填入缓冲区等到一定条件时会一次性写入文件里面减少了CPU的操作次数4.可移植性系统IO--不可移植只能在Linux中使用标准IO--可移植性强因为是属于C语言标准库中的函数只要能够使用C语言的情况下都是可以使用的4.标准IO和系统IO的应用场景标准IO的使用场景读写文本记事本、word文档、二进制文件音频、视频理由标准IO的缓冲区机制能够提高对于文本的快速操作系统IO的使用场景用于操作硬件设备的驱动文件、网络通信理由一般这类文件都是由操作系统提供的接口使用系统IO能够减少接口之间不同导致的问题对于这类文件一般都需要实时性如果使用标准IO,由于存在缓冲区不能在调用fread后立马写入到设备文件中出现滞后的现象