Linux系统编程笔记(六):文件I/O详解

Linux系统编程笔记(六):文件I/O详解

在 Linux 下一切皆文件,文件 I/O 是我们与内核交互最基本的方式。本篇笔记将从 man 手册的使用开始,逐步拆解系统调用、文件描述符、读写函数以及参数传递等核心概念,希望能帮助刚入门的同学理清思路。


一、man 手册:你的第一参考书

在 Linux 下遇到不认识的函数,第一反应应该是 manman man 可以查看 man 手册本身的说明,它共分为 9 个章节,实际使用中我们最常关注前 3 章:

  • 1 可执行程序或 shell 指令
  • 2 系统调用(内核提供的函数)
  • 3 库调用
  • 4 特殊文件
  • 5 文件格式和规范
  • 6 游戏
  • 7 杂项
  • 8 系统管理指令
  • 9 内核例程

经验之谈:当你想查 openread 这类函数时,记得用 man 2 open,否则可能看到的是 shell 命令 open 的解释。


二、系统调用的本质

系统调用是内核提供给外部访问 Linux 操作系统的一系列函数接口。应用程序通过系统调用陷入内核态,由内核完成实际的操作后返回结果。

理解系统调用,有助于我们区分"库函数"和"系统调用":库函数在用户态实现,可能封装了多个系统调用;而系统调用直接与内核交互,代价更高。


三、文件操作函数

1. 打开文件

c 复制代码
int open(const char* pathname,int flags);
//参数1 :打开文件的路径名
//参数2:打开文件的方式
	//O_RDONLY|O_WRONLY|O_RDWR --- <fcntl.h>


int open(const char *pathname, int flags, mode_t mode);

//参数3使用的前提是参数二指定了 O_CREAT
//mode意思为权限 参数包括rwx 也可以传8进制0664
c 复制代码

注意 open 函数的第二个参数 flags 必须包含 O_RDONLYO_WRONLYO_RDWR 三者之一,这是"访问模式"。第三个参数 mode 只有在 flags 中指定了 O_CREAT 时才有效,用于指定新建文件的权限。

2. 文件创建权限与 umask

Linux 系统中,创建文件的最终权限并不是 openmode 参数直接决定的,它还会受到进程的文件屏蔽码 umask 影响。

计算公式为:

text 复制代码
最终文件权限 = mode & ~umask

(原笔记写作 mode&-umask,其实隐藏了按位取反的逻辑,实际使用中请务必用 ~umask

小技巧:在 shell 里执行 umask 可以查看当前进程的屏蔽码,常见的 0022 表示屏蔽掉组和其他用户的写权限。

3. 文件读写

  • 读文件
c 复制代码
ssize_t read(int fd,void* buf,size_t count);
//按字节读
fd:文件描述符
buf存储缓冲区
count:缓冲区大小
返回值
    成功
    	未读到文件末尾》0
    	读到:0
 
    失败:-1
  • 写文件
c 复制代码
ssize_t write(int fd,const void *buf,size_t count);
//按字节写入
fd:文件描述符
buf存储待写出缓冲区
count:数据大小
返回值
    成功
    	>0实际写出的字节数
    	=0没写出数据
 
    失败:-1

readwrite 都是按字节操作的,非常底层。返回值要特别注意:read 返回 0 表示读到文件末尾,返回 -1 表示出错;write 返回 0 表示没写出数据(通常不会发生),返回 -1 表示出错。

4. 错误处理

Linux 系统调用失败时通常会返回 -1,并设置全局错误号 errno。我们可以用以下两个函数来获取错误描述:

c 复制代码
# include<string.h>
char* strerror(int errnum);
参数为错误号
    返回值为错误号对应的错误描述
c 复制代码
# include<stdio.h>
void perror(const char* s);
参数为用户自定义的错误信息 

strerror 需要传入错误号,返回对应的字符串描述;perror 则会把 errno 当前的错误描述打印出来,并自动加上用户传入的前缀。

5. 预读入缓输出

Linux 对文件 I/O 做了内核缓冲处理,读操作会预读入数据到内核缓冲区,写操作则先缓存在缓冲区,再由内核统一写出,这样能显著提升性能。

这里所说的"预读入"和"缓输出"是内核层面的机制,和我们用户态的 stdio 缓冲不是一回事。不过 stdio 也有自己的缓冲区,比如 fread/fwrite,使用时注意区分。

6. 文件描述符

  • PCB(进程控制块)本质上是一个结构体,其中包含一个文件描述符表。
  • 文件描述符范围:0/1/2/3/4/5/6/.../1023
    • 默认最大上限可以用 ulimit -a 查看
  • 文件描述符表的使用规则:使用表中未被占用的最小文件描述符

三个特殊文件:

  • stdin:标准输入 - 0 - STDIN_FILENO
  • stdout:标准输出 - 1 - STDOUT_FILENO
  • stderr:标准错误 - 2 - STDERR_FILENO

以后写程序时,如果不小心关闭了 stdout,那么再打开的第一个文件就会占用文件描述符 1。这种细节会直接影响输入输出行为,调试时务必留意。

7. 阻塞与非阻塞

阻塞、非阻塞是设备文件、网络文件具备的属性(不是 read/write 的属性)。

产生阻塞的场景主要有:

  • 读设备文件
  • 读网络文件

读常规文件则没有阻塞的概念。比如终端文件 /dev/tty,默认是阻塞的,如果用户不输入,read 会一直卡住。我们也可以把它设置为非阻塞:

c 复制代码
open("/dev/tty",O_RDWE|O_NONBLOCK); 

注意:示例中的 O_RDWE 疑似笔误,正确应为 O_RDWRO_RDONLY 等访问模式标志,实际使用时请参照 fcntl.h 中定义。

8. lseek 函数

c 复制代码
off_t lseek(int fd,offJ_t offset,int whence);
fd:文件描述
offset:偏移量 正数向后 负数向前
whence:起始偏移位置,SEEK_SET/SEEK_CUR/SEEKs_END
返回值:
    成功返回起始位置的偏移

(代码示例中的 offJ_t 应理解为 off_t,请勿照抄)

相关知识:

  • 文件的"读""写"使用的偏移位置是同一个位置
  • 可以使用 lseek 获取文件大小
  • 可以使用 lseek 拓展文件大小,但要使文件大小真正发生拓展,必须要有 I/O 操作介入
    • 直接拓展文件,也可以使用 truncate() 函数来完成

四、传入参数、传出参数与传入传出参数

函数参数是指针时,在 C 语言中非常常见。根据数据的流动方向,我们可以把参数分为三类:

1. 传入参数

  • 例子:write 的第 2 参、strcpy 的第 2 参
  • 特点:
    1. 指针做函数参数
    2. 通常有 const 修饰
    3. 指针指向有效区域,在函数内做读操作

2. 传出参数

  • 例子:strcpy 的第 1 参
  • 特点:
    1. 指针做函数参数
    2. 在函数调用前,指针指向的空间可以无意义但必须有效
    3. 在函数内部做写操作
    4. 函数调用结束后充当函数返回值

3. 传入传出参数

  • 例子:strtok 的第 3 参
  • 特点:
    1. 指针做函数参数
    2. 在函数调用之前指针指向的空间有效且有实际意义
    3. 在函数内部,先做读操作,后做写操作
    4. 函数调用结束后,充当函数返回值

理解这三类参数,对阅读源代码和设计接口都非常有帮助。尤其是"传出参数",经常用来替代多个返回值的情况,这是 C 语言的一种常见编程手法。


总结

本篇笔记梳理了 Linux 文件 I/O 的若干核心概念:man 手册、系统调用、open/read/write、错误处理、文件描述符、阻塞/非阻塞、lseek 以及参数传递方向。掌握这些基础,后续学习重定向、管道、socket 等高级 I/O 会轻松很多。希望这篇笔记对你有所帮助,欢迎在评论区交流讨论!

相关推荐
小德车机导航4 天前
【资源编号:317】高德车机版 9.5.0.60006
教程·技术
小德车机导航6 天前
资源编号334_高德地图 9.5.13 版本经典远山风景
教程·技术
网络研究院9 天前
世纪谍战史诗:布莱切利园与纳粹密码的无声终结
技术·科学·情报·战争·秘密
czysoft1 个月前
se被限速
科技·学习·it·技术·魔法·先进·领先
小德车机导航2 个月前
【资源编号:292】高德地图 v16.17.3.1403 低配车机专属定制修改版
教程·技术
hanbr2 个月前
[特殊字符] Linux 学习笔记(二):压缩、Vim 与配置
linux·技术
小德车机导航2 个月前
839个青龙签到脚本免费下载|自动签到脚本合集,持续更新中
教程·技术
AAA_Ethan2 个月前
2026餐饮供应链测评:中高端餐厅如何筛选高品质竹笋供应商?
技术·餐饮
小德车机导航2 个月前
关于高德地图 V16.18.0.1141 手机版 修改思路说明
教程·技术