认识 C 语言的文件 I/O
在学习 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 ) |
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 中,打开文件常用:
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:功能丰富,有缓冲区,适合日常开发。
系统调用:直接、底层、安全,适合对性能和控制要求高的场景。
两者可以互相结合使用。
缓冲机制是提高效率的关键,但也要注意及时刷新。
理解了这套机制,你就能在不同场景下选择最合适的文件操作方法。