在学习 C 语言时,文件输入输出(I/O)是绕不开的一部分。很多初学者觉得这块很复杂,其实只要掌握几个核心概念,就能顺畅地读写文件、操作数据了。
1. I/O
I/O 是 Input(输入) 和 Output(输出) 的缩写。
在 C 语言中,标准输入 默认是键盘,标准输出 默认是显示器。
在 Linux 里,几乎所有 I/O 都是“文件操作”,即使是键盘、屏幕、网络,都可以用文件的方式去读写。
2. 两种 I/O 方式
C 语言中常见的文件操作有两种:
1.标准 I/O(库函数)
-
使用 FILE *fp 这种指针。
-
常用函数:fopen、fgetc、fputs、fread、fwrite、fseek、fclose。
-
有 缓冲机制:数据会先存在内存的缓冲区里,不是直接读写硬盘,提高效率。
-
优点:功能多、用起来简单。
-
缺点:安全性稍弱,跨平台时个别行为可能不同。
2.系统调用(文件 I/O)
-
使用 文件描述符 fd(一个整数)。
-
常用函数:open、read、write、lseek、close。
-
直接跟操作系统交互,没有缓冲区。
-
优点:简单、直接、安全。
-
缺点:功能不如标准 I/O 丰富,需要自己处理细节。
-
其实,标准 I/O 底层就是用系统调用实现的。
3.缓冲区域
为了减少读写次数,提高速度,标准 I/O 会先把数据放进缓冲区,然后一次性处理。
有三种缓冲方式:
行缓冲 | 约 1KB | 遇到 \\n、缓冲满、fflush、程序结束 | 与终端交互(stdout) |
全缓冲 | 约 4KB | 缓冲满、fflush、程序结束 | 文件读写 |
无缓冲 | 0 | 立即输出 | 错误信息(stderr) |
例子:
printf("Hello"); // 行缓冲,可能暂时不输出
fflush(stdout); // 手动刷新缓冲区
4.文件定位
有时需要移动“文件指针”,比如跳过前几个字节。
标准 I/O 的定位函数:
-
fseek(fp, offset, whence):移动文件位置。
-
ftell(fp):获取当前位置。
-
rewind(fp):回到文件开头。
系统调用的定位函数:
-
lseek(fd, offset, whence):同样功能,只是操作文件描述符。
whence 取值:
-
SEEK_SET:文件开头
-
SEEK_CUR:当前位置
-
SEEK_END:文件结尾
5. 文件权限与 open 函数
在 Linux 中,打开文件常用:
int open(const char *pathname, int flags, mode_t mode);
-
flags 必选:
-
O_RDONLY(只读)
-
O_WRONLY(只写)
-
O_RDWR(读写)
-
-
flags 附加:
-
O_APPEND(追加写)
-
O_CREAT(文件不存在则创建)
-
O_TRUNC(截断清空)
-
-
mode:创建文件时的权限,如 0666(读写权限)。
权限会受 umask 影响,实际权限 = mode & ~umask。
6. 标准 I/O 与系统调用的互转
有时需要把 FILE * 和 fd 互相转换:
-
fileno(fp):从流指针得到文件描述符。
-
fdopen(fd, "r+"):从文件描述符创建流指针。
小练习
用 read 和 write 复制文件:
int fd1 = open("src.txt", O_RDONLY);
int fd2 = open("dst.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
char buf[1024];
ssize_t n;
while ((n = read(fd1, buf, sizeof(buf))) > 0) {
write(fd2, buf, n);
}
close(fd1);
close(fd2);
总结
-
标准 I/O:功能丰富,有缓冲区,适合日常开发。
-
系统调用:直接、底层、安全,适合对性能和控制要求高的场景。
-
两者可以互相结合使用。
-
缓冲机制是提高效率的关键,但也要注意及时刷新。
理解了这套机制,你就能在不同场景下选择最合适的文件操作方法。
我可以帮你把这篇博客配上文件 I/O 结构图,让初学者一看就懂。
你要我帮你画这个图吗?这样整篇会更直观。
评论前必须登录!
注册