
目录1. 引言2. 系统调用接口2.1 open 函数2.2 write 与 read2.3 close3. 文件描述符File Descriptor, fd3.1 默认打开的三个文件描述符3.2 文件描述符的本质3.3 文件描述符分配规则4. 重定向的原理4.1 输出重定向示例4.2 使用 dup2 系统调用5. 小结1. 引言C标准库的fopen等函数最终调用的是系统调用。本文直接使用系统调用接口open、read、write、close进行文件操作并重点讲解文件描述符的概念、分配规则以及重定向的底层原理。2. 系统调用接口2.1open函数c#include sys/types.h #include sys/stat.h #include fcntl.h 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不存在则创建、O_APPEND追加、O_TRUNC截断。mode当使用O_CREAT时指定新文件的权限如0644会受到进程umask的影响。可通过umask(0)临时清除掩码。返回值成功返回一个非负整数——文件描述符失败返回 -1。2.2write与readcssize_t write(int fd, const void *buf, size_t count); ssize_t read(int fd, void *buf, size_t count);fd文件描述符。返回值成功返回实际读/写的字节数出错返回 -1。2.3closecint close(int fd);关闭文件描述符释放相关资源。3. 文件描述符File Descriptor, fd3.1 默认打开的三个文件描述符Linux进程启动时默认打开三个文件描述符0标准输入stdin1标准输出stdout2标准错误stderr它们对应的物理设备通常是键盘和显示器。我们可以直接使用read(0, buf, size)从键盘读入使用write(1, buf, len)输出到屏幕。3.2 文件描述符的本质文件描述符是一个小整数它是进程打开文件表的索引。内核为每个进程维护一个files_struct结构体其中包含一个指针数组fd_array[]每个元素指向一个struct file对象表示一个打开的文件。文件描述符就是这个数组的下标。3.3 文件描述符分配规则规则在当前进程中fd_array[]中找到最小的未被使用的下标分配给新打开的文件。验证实验正常打开一个文件输出fd通常为3因为0、1、2已被占用。先调用close(0)或close(2)再打开文件则新文件的fd将成为0或2。4. 重定向的原理4.1 输出重定向示例cclose(1); // 关闭标准输出 int fd open(myfile, O_WRONLY | O_CREAT, 0644); printf(fd: %d\n, fd); // 这里 fd 为 1 fflush(stdout);现象printf的内容没有出现在屏幕上而是写入了myfile文件。这是因为close(1)释放了下标1随后open分配了最小的可用下标1于是文件描述符1现在指向了myfile对应的struct file。printf底层向stdout即 fd1写入数据数据便进入了文件。重定向的本质改变文件描述符下标对应的struct file指针使其指向不同的打开文件。4.2 使用dup2系统调用dup2可以更便捷地实现重定向c#include unistd.h int dup2(int oldfd, int newfd);功能让newfd指向oldfd所指向的文件如果newfd已打开则先关闭它。示例实现输出重定向cint fd open(log, O_CREAT | O_RDWR, 0644); dup2(fd, 1); // 将标准输出重定向到 fd 对应的文件 printf(这条消息将写入 log 文件\n);同理输入重定向使用dup2(fd, 0)追加重定向使用O_APPEND标志打开文件后再dup2。5. 小结本文详细介绍了系统级文件I/O接口、文件描述符的概念、分配规则以及重定向的底层原理。下一篇我们将把这些知识应用到之前实现的迷你Shell中为Shell添加完整的重定向功能。