一、标准 IO vs 文件 IO:库函数与系统调用的本质区别
今天系统学习了 Linux 下的文件 IO 和目录 IO,这一块和标准 IO 最大的区别就是:标准 IO 是库函数,文件 IO 是系统调用。
标准 IO(stdio.h)
- 性质:属于 C 库函数,是对系统调用的封装。
- 特点:自带用户层缓冲区,可移植性好,适合普通文件读写。
- 局限:不适合直接操作设备文件、网络通信等场景。
文件 IO(unistd.h、fcntl.h)
- 性质 :属于 Linux 系统调用,直接和内核打交道。
- 特点 :无用户层缓冲区,移植性差(与操作系统强相关)。
- 适用场景:操作硬件、串口、网络设备等底层资源。
一句话记住:库函数封装系统调用;系统调用是内核给用户的接口。
二、四大文件 IO 函数:open / close / read / write / lseek
1. open - 打开或创建文件
c
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
- pathname:文件路径
- flags 常用标记 :
O_RDONLY:只读O_WRONLY:只写O_RDWR:读写O_CREAT:文件不存在就创建,必须给第三个参数 mode 权限O_EXCL:文件存在则报错,常和O_CREAT搭配使用O_TRUNC:文件存在则清空内容O_APPEND:追加写入
- 返回值 :成功返回文件描述符 fd (最小可用的非负整数),失败返回
-1
三个默认文件描述符:
0:标准输入 stdin1:标准输出 stdout2:标准错误 stderr
标准 IO 与文件 IO 打开模式对照表:
| 标准 IO 模式 | 文件 IO 等效 flags |
|---|---|
"r" |
O_RDONLY |
"r+" |
O_RDWR |
"w" |
`O_WRONLY |
"w+" |
`O_RDWR |
"a" |
`O_WRONLY |
"a+" |
`O_RDWR |
2. write - 写入数据
c
ssize_t write(int fd, const void *buf, size_t count);
- 往文件描述符
fd指向的文件中写入count个字节 - 数据来源:缓冲区
buf - 返回值:成功返回实际写入的字节数,出错返回
-1
3. read - 读取数据
c
ssize_t read(int fd, void *buf, size_t count);
- 从文件描述符
fd指向的文件中读取最多count个字节 - 数据存储:存入缓冲区
buf - 返回值:
- 成功:返回实际读取的字节数
- 文件结束:返回
0 - 出错:返回
-1
4. lseek - 移动文件读写位置
c
off_t lseek(int fd, off_t offset, int whence);
- 移动文件读写偏移量(文件指针)
- whence 参数 :
SEEK_SET:从文件开头偏移offsetSEEK_CUR:从当前位置偏移offsetSEEK_END:从文件末尾偏移offset
- 返回值:成功返回偏移后距离文件开头的总偏移量,失败返回
(off_t)-1
经典练习 :使用
open-read-write组合实现图片拷贝功能。
三、目录 IO(遍历文件夹核心)
头文件:<dirent.h>
1. opendir - 打开目录
c
DIR *opendir(const char *name);
- 打开指定目录,返回目录流指针
DIR* - 失败返回
NULL
2. closedir - 关闭目录
c
int closedir(DIR *dirp);
- 关闭目录流
- 成功返回
0,失败返回-1
3. readdir - 读取目录项
c
struct dirent *readdir(DIR *dirp);
- 读取目录中的下一项
- 返回
struct dirent指针,包含目录项信息 - 读到末尾或出错时返回
NULL
重点成员:
d_name[256]:文件/目录名字符串
实际应用 :上周遍历
~/Music目录筛选音视频文件,就是用opendir+readdir循环读取文件名,然后判断后缀名。
4. chdir & getcwd - 工作目录操作
-
获取当前工作目录 :
cchar *getcwd(char *buf, size_t size); -
修改进程当前工作目录 :
cint chdir(const char *path);
四、易错点与注意事项
-
open 权限问题:
- 使用
O_CREAT标志时,一定要传递 mode 权限参数,否则创建的文件权限可能不符合预期。
- 使用
-
文件描述符分配原则:
- 遵循最小可用分配原则:0、1、2 被占用后,新打开的文件会依次分配 3、4、5...
-
缓冲区差异:
- 文件 IO 没有用户层缓冲区 ,
write调用直接进入内核 - 标准 IO 有缓冲区,需要
fflush或文件关闭时才真正落盘
- 文件 IO 没有用户层缓冲区 ,
-
read 返回值理解:
- 返回
0:表示已到达文件末尾(EOF),不是错误 - 返回
-1:表示读取过程中发生错误
- 返回
-
目录遍历注意事项:
readdir会读取到当前目录(.)和父目录(..)- 遍历时记得跳过这两个特殊目录项,避免无限循环或逻辑错误
五、总结
Linux 文件 IO 和目录 IO 是系统编程的基础,理解它们与标准 IO 的区别至关重要:
- 文件 IO 是底层系统调用,直接与内核交互,适合需要精细控制的场景
- 标准 IO 是高层库函数,提供缓冲和便捷接口,适合普通应用开发
- 目录 IO 提供了遍历文件系统的标准方法,是许多工具和应用程序的基础
掌握这些系统调用,不仅能编写更高效的程序,还能深入理解 Linux 系统的工作机制。