作者说明 · 学习记录
本站作为作者的学习记录站,不保证文章内容严谨或完全正确。
版权信息

warning

本文章为博主原创文章。遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。


文件描述符:内核分发的身份证

在 Linux 系统中,文件描述符(File Descriptor,简称 FD)是一个核心概念,它是一个非负整数,用于唯一标识一个已打开的文件。这个文件可以是普通文件、目录、网络套接字(socket),甚至是设备(如键盘、显示器)。

文件描述符的设计主要有以下几个优点:

  1. 简化了 I/O 接口:无论是读写本地文件,还是进行网络通信,开发者都可以使用一套统一的系统调用(read, write, close 等),而无需关心底层的具体类型。这种“一切皆文件”的设计哲学是 Linux 简洁和强大的体现。

  2. 隔离了应用程序与内核:应用程序只知道一个简单的整数,而不需要知道文件在磁盘上的物理位置,也不用关心内核是如何管理文件的。所有复杂的操作都由内核在幕后完成。

  3. 管理系统资源:内核通过文件描述符表来管理每个进程打开的文件。当一个进程结束时,内核可以根据这个表自动关闭所有打开的文件,避免资源泄露。

文件描述符的几个重要特点:

最基础的系统调用函数

Linux I/O 编程中常见的系统调用函数,这些函数位于 unistd.h(以及 fcntl.h 等)中,是用户态和内核态交互的基础接口。

1. open

1
2
3
4
5
6
7
#include <fcntl.h>    // open flags
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

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

作用

打开或创建一个文件,返回一个 文件描述符(fd,整数),后续 I/O 都依赖它。

参数

返回值


2. write

1
2
3
#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);

作用

向文件(或设备)写入数据。

参数

返回值

注意


3. read

1
2
3
#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

作用

从文件(或设备)读取数据。

参数

返回值

注意


4. lseek

1
2
3
#include <unistd.h>  

off_t lseek(int fd, off_t offset, int whence);

作用

移动文件读写位置(文件指针)。

参数

返回值

注意


5. close

1
2
3
#include <unistd.h>

int close(int fd);

作用

关闭一个打开的文件描述符,释放内核资源。

参数

返回值

常见函数查找表

函数 头文件 功能 主要参数 返回值 常见用途
open <fcntl.h>, <unistd.h> 打开或创建文件,返回文件描述符 pathname:路径flags:打开方式(如 O_RDONLYmode:权限(如 0644,仅在 O_CREAT 时有效) 成功:文件描述符 (≥0)失败:-1 打开文件/设备,获得 fd
write <unistd.h> 向文件写入数据 fd:文件描述符buf:数据缓冲区count:要写入字节数 成功:实际写入字节数失败:-1 向文件、管道、socket 写数据
read <unistd.h> 从文件读取数据 fd:文件描述符buf:存放数据的缓冲区count:最大读取字节数 成功:实际读取字节数0:文件结尾失败:-1 读取文件、键盘输入、网络数据
lseek <unistd.h> 改变文件读写位置(文件指针) fd:文件描述符offset:偏移量whence:参考位置(SEEK_SET/SEEK_CUR/SEEK_END 成功:新的偏移位置失败:-1 随机读写文件、获取文件大小
close <unistd.h> 关闭文件描述符,释放资源 fd:文件描述符 成功:0失败:-1 程序结束或文件不再使用时关闭
sync <unistd.h> 将内核缓冲区中所有修改过的数据(脏页)写入磁盘 无返回值 全局刷新,影响所有文件,效率较低
fsync <unistd.h> 将指定文件的缓存数据强制写入磁盘 fd:文件描述符 成功:0,失败:-1 精确到单个文件,常用于数据库、日志写入
pipe <unistd.h> 创建匿名管道,用于进程间通信 int pipefd[2] 成功:0,失败:-1 pipefd[0] 读端,pipefd[1] 写端
unlink <unistd.h> 删除一个文件(目录用 rmdir pathname:文件路径 成功:0,失败:-1 实际删除在引用计数归零时发生
access <unistd.h> 检查文件是否存在及权限 pathname, mode 成功:0,失败:-1 mode 可取 R_OK, W_OK, X_OK, F_OK

对比C 标准库IO操作

使用c标准库的IO操作,小量频繁读写的效率更高,因为其内部自带有缓冲区。
这可以理解为在系统IO上有封装了一层,进行文件操作时写入C自带缓冲区,满足一定条件再调用系统IO,将缓冲区的内容写入IO缓存区,再到内核的页缓存区,最后到物理的磁盘。

特性 Linux 系统调用 I/O C 标准库文件操作
头文件 <unistd.h>, <fcntl.h> <stdio.h>
函数示例 open, read, write, lseek, close fopen, fread, fwrite, fseek, fclose, fprintf, fscanf
返回值 直接返回字节数、文件描述符等,或 -1 返回 FILE* 指针,或 EOF 等错误码
数据单位 字节(byte) 为单位 缓冲区 / 结构化数据 为单位(有缓冲机制)
缓冲 无用户态缓冲,直接在用户空间和内核空间间传递数据 带缓冲区(stdio 库内部维护缓存,加速小块读写)
层次 操作系统内核提供的 底层接口 基于系统调用的 封装库函数
灵活性 可操作普通文件、设备文件、socket、管道 主要操作普通文件和标准输入输出
可移植性 偏向 Unix/Linux 系统 跨平台(符合 ANSI C 标准,Windows/Linux 通用)
典型用途 驱动开发、系统编程、精确控制 I/O 应用层文件读写、文本处理、快速开发

Linux 系统IO编程

创建时间:9月 09, 2025

最后更新:9月 09, 2025

字数统计:2.1k字

预计阅读:7min