文件描述符+文件流指针+缓冲区

本文深入解析了文件描述符的概念及其在操作系统中的作用,详细阐述了文件描述符与文件流指针之间的关系,以及如何通过文件描述符进行文件操作,包括重定向、dup和dup2函数的使用。

文件描述符fd

文件描述符就是一个小的正整数,是内核中文件描述信息结构体数组的下标,对应有一个文件描述信息来操作文件

当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进 程和文件关联起来。每个进程都有一个指针files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数 组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件 描述符,就可以找到对应的文件
在这里插入图片描述
struct files_struct里面包含了结构体指针数组struct file
[ ],数组中存放的是指向struct file的地址,通过找到struct file就可以找到文件

文件描述符的分配规则- - - 最小未使用

在这里插入图片描述
文件描述符和文件流指针的关系
文件描述符可以直接操作文件,但是不方便,所以封装接口,增加功能,变成了文件流指针
同库函数与系统调用接口一样,库函数可以看作是对系统调用接口的封装
库函数操作的是文件流指针(FILE*类型的结构体指针数组)
系统调用接口操作的是文件描述符(int 类型的整数)
重定向
重定向指的是文件描述符的重定向;如果文件描述符这个下标的文件描述信息从一个文件变成了另一个文件,当用户通过文件描述符向文件写入数据时,数据就因为描述符信息的改变而流向另一个文件
简单来说,就是讲要写入文件A的数据写入到另一个文件

两种重定向
>>		追加重定向		即 O_APPEND
>		清空重定向		即 O_TRUNC

dup
dup的主要功能是将oldfd对应的描述信息拷贝一份到newfd,新旧文件描述符都指向同一个文件,这里主要说明常用的dup2

int dup2(int oldfd,int newfd);		让newfd重定向到oldfd

功能:将oldfd描述符对应的描述信息向newfd拷贝一份
让newfd也指向oldfd所指向的文件
若newfd本身已经有打开的文件,则关闭这个文件

fd=open(./test.txt);
dup2(fd,1);		把1重定向到fd所指向的文件,1也指向test.txt这个文件
fd=open(./test.txt,O_APPEND);
dup2(fd,1);		把1重定向到fd所指向的文件,再次写入时写到文件最后

用户态缓冲区
先看代码

printf("hello world");	//库函数
fprintf("hello world");	//系统调用接口

printf打印的数据不会立即被写入到标准输出文件中,而是先将数据写入到一块缓冲区中,等到缓冲区写满或者用户手动刷新缓冲区fflush,才会将数据一次性写入文件中;
我们通常所说的缓冲区值得就是文件流指针中描述的缓冲区,系统调用是没有这个缓冲区的,这个缓冲区通常也被称为用户态缓冲区

### 文件描述符文件流指针的区别与联系 #### 一、基本概念 文件描述符(File Descriptor, FD)是一个非负整数,由操作系统分配给每个打开的文件或设备。它是进程文件描述符表中的索引,用于标识当前进程中已打开的文件资源[^2]。 文件流指针(`FILE *`)则是 C/C++ 编程语言中的一种数据结构,通常用于高级 I/O 操作。它封装了底层的文件描述符以及其他元信息(如缓冲区状态),提供了更友好的接口供开发者使用[^5]。 --- #### 二、主要区别 1. **层次不同** - 文件描述符属于操作系统层面的概念,直接对应于内核维护的文件对象。 - 文件流指针则位于应用层,是对文件描述符的一次封装,便于程序员进行更高层次的操作[^4]。 2. **功能范围** - 文件描述符仅支持低级操作,例如 `read()`、`write()`、`close()` 等系统调用。 - 文件流指针除了能够完成类似的读写操作外,还额外支持格式化输入输出(如 `fprintf()`、`fscanf()`)、错误处理机制以及自动缓冲管理等功能[^5]。 3. **实现方式** - 文件描述符本质上只是一个整数值,在 Linux 或其他类 Unix 系统下代表某个特定的文件或者网络连接等资源。 - 而 FILE 结构体内部包含了指向实际文件描述符的字段(比如 `_fileno` 成员变量)。这意味着可以通过访问该成员获取到关联的基础文件描述符[^5]。 4. **跨平台特性** - 使用文件描述符编写程序具有良好的可移植性,因为几乎所有现代操作系统都遵循 POSIX 标准实现了统一 API 集合。 - 对应地,尽管标准库定义了一致的行为模式,但由于具体实现细节可能有所差异,因此基于文件流开发的应用可能会遇到兼容性问题[^3]。 --- #### 三、两者之间的关系 虽然它们分属不同的抽象级别,但在某些情况下可以互相转换: - 在 C 库函数的帮助下,可以从现有的文件流创建一个新的独立副本并获得相应的新文件描述符;反之亦然——利用 fdopen 函数可以把原始裸露出来的数字型句柄重新包装成易于使用的 stream object 形式[^5]。 下面展示一段简单的例子说明如何在这两种形式之间切换: ```c #include <stdio.h> #include <unistd.h> int main() { int fd = fileno(stdin); // 获取 stdin 的文件描述符 printf("Standard Input File Descriptor: %d\n", fd); FILE* fp = fdopen(1, "w"); // 将 stdout (file descriptor '1') 转换回 file pointer fprintf(fp, "This is written via a FILE pointer.\n"); fclose(fp); return 0; } ``` 此代码片段先是从预设的标准输入提取出它的基础编号表示法即文件描述符,接着又演示怎样把另一个方向上的标准化输出端口映射回去形成新的高级别 IO 接口实例。 --- ### 总结 综上所述,文件描述符文件流指针各有优劣之处:前者更加贴近硬件本质且效率较高但灵活性较差;后者虽牺牲了一些性能却极大地简化了复杂场景下的编码工作量并且增强了安全性保障措施。根据项目需求合理选用合适的工具才是最重要的原则之一。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值