【Linux】系统级文件I/O与文件描述符深度剖析

目录

[1. 引言](#1. 引言)

[2. 系统调用接口](#2. 系统调用接口)

[2.1 open 函数](#2.1 open 函数)

[2.2 write 与 read](#2.2 write 与 read)

[2.3 close](#2.3 close)

[3. 文件描述符(File Descriptor, fd)](#3. 文件描述符(File Descriptor, fd))

[3.1 默认打开的三个文件描述符](#3.1 默认打开的三个文件描述符)

[3.2 文件描述符的本质](#3.2 文件描述符的本质)

[3.3 文件描述符分配规则](#3.3 文件描述符分配规则)

[4. 重定向的原理](#4. 重定向的原理)

[4.1 输出重定向示例](#4.1 输出重定向示例)

[4.2 使用 dup2 系统调用](#4.2 使用 dup2 系统调用)

[5. 小结](#5. 小结)


1. 引言

C标准库的 fopen 等函数最终调用的是系统调用。本文直接使用系统调用接口 openreadwriteclose 进行文件操作,并重点讲解文件描述符的概念、分配规则以及重定向的底层原理。

2. 系统调用接口

2.1 open 函数

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_RDONLYO_WRONLYO_RDWR 之一,可与其他标志按位或,如 O_CREAT(不存在则创建)、O_APPEND(追加)、O_TRUNC(截断)。

  • mode:当使用 O_CREAT 时,指定新文件的权限(如 0644),会受到进程 umask 的影响。可通过 umask(0) 临时清除掩码。

返回值: 成功返回一个非负整数------文件描述符;失败返回 -1。

2.2 writeread

c

复制代码
ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count);
  • fd:文件描述符。

  • 返回值:成功返回实际读/写的字节数,出错返回 -1。

2.3 close

c

复制代码
int close(int fd);

关闭文件描述符,释放相关资源。

3. 文件描述符(File Descriptor, fd)

3.1 默认打开的三个文件描述符

Linux进程启动时,默认打开三个文件描述符:

  • 0:标准输入(stdin)

  • 1:标准输出(stdout)

  • 2:标准错误(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 将成为 02

4. 重定向的原理

4.1 输出重定向示例

c

复制代码
close(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 fileprintf 底层向 stdout(即 fd=1)写入数据,数据便进入了文件。

重定向的本质: 改变文件描述符下标对应的 struct file 指针,使其指向不同的打开文件。

4.2 使用 dup2 系统调用

dup2 可以更便捷地实现重定向:

c

复制代码
#include <unistd.h>
int dup2(int oldfd, int newfd);

功能:让 newfd 指向 oldfd 所指向的文件,如果 newfd 已打开,则先关闭它。

示例:实现输出重定向

c

复制代码
int 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添加完整的重定向功能。

相关推荐
guo_wen_qiang2 小时前
mac中docker desktop服务端开启远程访问
运维·服务器·macos·docker
小五传输3 小时前
消防总队信创改造实践:国产文件传输服务器解决文件传输难题
大数据·运维·安全
云飞云共享云桌面3 小时前
医疗器械设备研发:多人同时操作 SolidWorks,怎样依靠单台服务器替代多工作站
运维·服务器·网络·数据库·制造
T型码农要学习3 小时前
开源项目5|FileBrowser:免费在线文件管理器!随时随地管控服务器文件
运维·服务器·人工智能·开源
朱 欢 庆3 小时前
云服务器附件备份到本机内网服务器
运维·服务器·前端·经验分享
梦想不只是梦与想3 小时前
Web 服务器网关协议:ASGI 和 WSGI
服务器·python·fastapi
智恒百亿3 小时前
8 卡 RTX 5090 服务器深度实测:256GB 显存能否支撑 70B 模型微调?选型参考
大数据·运维·服务器·人工智能
志栋智能8 小时前
超自动化运维如何支持合规审计?
运维·自动化
小诗懂技术8 小时前
【网络通信UDP】基础 进程间不同主机的通信
运维·服务器·网络
weixin_440730509 小时前
selenium实战记录-从登陆-首页-进入应用流程用例三种参数化+日志+报告
服务器·selenium·测试工具