Linux软件编程(2)IO
这两天学习了C语言标准文件IO相关内容。标准IO是我们操作文件的基础,不管是读取文本词典、读写配置文件,还是复制图片这类二进制文件,都离不开这套接口。
一、基础概念
文件本质是存放在磁盘上的一段数据集合。在C语言中操作文件,固定分为三步:打开文件、读写文件、关闭文件。
我们操作文件时,程序和文件之间会建立流。流具备方向性与连续性。程序启动时,系统会默认打开三个流:标准输入流stdin、标准输出流stdout、标准错误流stderr,也就是我们平时的键盘输入、屏幕打印输出。
文件分为ASCII文本文件和二进制文件。文本文件里全部是可正常显示的ASCII字符,比如我们写的C代码、txt笔记;二进制文件包含大量无法直接在终端展示的字符,图片、音视频、压缩包都属于二进制文件。文本文件可以用逐字符、逐行的函数读写,二进制文件一般使用fread、fwrite整块读写。
二、打开与关闭文件
fopen 打开文件
FILE *fopen(const char *pathname, const char *mode);
函数作用:找到路径对应的文件,建立程序与文件之间的数据流,返回FILE类型指针,后续所有读写操作都依靠这个指针。
打开模式有多种,常用规则:
- r:只读。文件不存在直接报错,只能读取已有文件内容。
- r+:读写。文件不存在报错,可读可写。
- w:只写。文件不存在则新建;文件存在,会清空原有内容,再写入数据。
- w+:读写。文件不存在新建,存在则清空原文件。
- a:追加只写。文件不存在新建,写入内容会放在文件末尾,不会覆盖旧数据。
- a+:追加读写。支持读取,写入的数据依旧追加在文件尾部。
函数调用失败会返回NULL,写完代码后必须判断返回值,避免空指针操作程序崩溃。
fclose 关闭文件
int fclose(FILE *stream);
文件使用结束后一定要调用fclose关闭流。关闭时会自动刷新缓冲区数据,释放资源。成功返回0,失败返回EOF。
三、缓冲区
标准IO自带缓冲区,我们调用读写函数时,数据不会直接交给操作系统内核,先存放在缓冲区,满足刷新条件后才完成真正传输。缓冲区分为三类:
- 全缓存:和普通文件建立的流属于全缓存,缓冲区大小4096字节。
刷新时机:缓冲区存满;主动调用fflush强制刷新;程序结束、调用fclose关闭流。 - 行缓存:和终端交互的流(stdin、stdout)属于行缓存,缓冲区大小1024字节。
刷新时机:缓冲区存满;fflush强制刷新;程序结束或关闭流;读到换行符\n。 - 无缓存:数据写入立刻生效,stderr标准错误流就是无缓存,适合报错、需要实时交互的场景。
四、读写常用函数
逐字符读写:fputc、fgetc
int fputc(int c, FILE *stream);
int fgetc(FILE *stream);
fputc:向流中写入单个字符,成功返回字符ASCII码,失败返回EOF。
fgetc:从流读取单个字符,读到文件末尾或者读取失败,都会返回EOF。
适合简单字符写入,也可以逐字符读取文件,统计文件行数。
逐字符串读写:fputs、fgets
int fputs(const char *s, FILE *stream);
char *fgets(char *s, int size, FILE *stream);
fputs:将字符串写入流,不会自动添加换行符,和puts有区别。
fgets:读取一行字符串。参数size代表最多读取字符数量;读取完成后字符串会自带读到的换行\n,不会自动丢弃,这一点和gets不同。读取失败或到达文件末尾,返回NULL。
格式化读写:fprintf
int fprintf(FILE *stream, const char *format, …);
用法和printf几乎一致,区别是printf默认输出到屏幕stdout,fprintf可以把格式化字符串写入指定文件流。
整块二进制读写:fwrite、fread
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
这一组函数多用于二进制文件操作,比如复制图片、音频。
ptr:数据存放的内存首地址;size:单个数据块字节大小;nmemb:一共读写多少个数据块。
返回值代表实际成功读写的数据块数量,读取到文件末尾或者出错,返回0。
五、文件偏移定位函数
文件读写时存在读写位置标记,默认从头开始读取,下面三个函数可以手动调整这个标记位置:
-
fseek
int fseek(FILE *stream, long offset, int whence);
whence有三个选项:
SEEK_SET:基准点为文件开头;
SEEK_CUR:基准点为当前读写位置;
SEEK_END:基准点为文件末尾。
offset代表相对基准点偏移多少字节,成功返回0,失败返回-1。 -
ftell
long ftell(FILE *stream);
获取当前读写位置距离文件开头的偏移字节数,常配合fseek获取整个文件长度。 -
rewind
void rewind(FILE *stream);
简化函数,直接把读写偏移定位回到文件开头,等价于 fseek(stream,0,SEEK_SET)。
标准IO整套接口是上层封装,使用起来更加便捷,自带缓冲区提升读写效率。学习时需要区分文本读写函数和二进制读写函数的适用场景,分清各个打开模式的差异,同时牢记文件用完必须关闭。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)