【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添加完整的重定向功能。

相关推荐
虾壳云官方1 小时前
openclaw 一键安装教程(2026年6月15最新)
运维·人工智能·windows·自动化·openclaw
ShineWinsu1 小时前
对于Linux:线程局部存储(TLS)和线程封装的解析
linux·c++·面试·线程·tls·线程封装·线程局部存储
2023自学中1 小时前
imx6ull开发板,sd卡启动运行linux,手动给开发板的 emmc 做分区、烧系统
linux·嵌入式·开发板
小陈phd1 小时前
LCEL(LangChain Expression Language)语法全解
服务器·网络·langchain
暮云星影1 小时前
瑞芯微rk3566开发FIT Secure Boot
linux·arm开发·驱动开发·安全
ctrl_v助手2 小时前
VisionPro (R) QuickBuild相机的连接
服务器·笔记·数码相机·c#
biter down2 小时前
2:Ubuntu 22.04 LTS 的完整下载教程
linux·运维·ubuntu
零陵上将军_xdr2 小时前
为什么DCL单例要加volatile?——CPU乱序执行与内存屏障
java·linux
杨云龙UP2 小时前
Oracle/ODA RAC /u01 空间告警处理指南:grid 用户监听日志清理_2026-06-15
linux·数据库·oracle·oracle linux·oda·监听日志·在线清理