Linux---文件描述符fd与FILE结构体

本文介绍了Linux中文件描述符的概念,作为识别文件的非负整数,其管理和分配规则,并通过示例说明了文件描述符在程序中的作用。同时,讨论了C语言中的FILE结构体,它在用户空间中用于文件操作,并包含文件描述符和缓冲区信息。最后,阐述了文件描述符与FILE结构体之间的关系,以及如何在两者之间进行转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文件描述符(file descriptor)

在Linux中不是用文件指针来识别一个文件,而是用文件描述符来识别的。
文件描述符简称fd,它是Linux内核所创建的索引,目的就是为了高效管理已经被打开的文件。它是一个非负整数,用来表示被打开的文件,而对该文件所有的I/O操作都是通过该文件的文件描述符来执行的。
在一个程序刚刚启动时,系统就已经占了三个文件描述符了,分别为:0(标准输入)、1(标准输出)、2(标准错误)。如果此刻程序再打开或创建一个新文件时,该文件的文件描述符将是3。因为文件描述符有自己的分配规则:将当前最小的未被使用的文件描述符分配给新创建的文件。

来一张图看看文件描述符是怎么管理文件的:
这里写图片描述

如果我们关闭了文件描述符1呢?来看一段代码:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

int main()
{
    close(1);
    int fd=open("file",O_CREAT|O_WRONLY,0644);
    if(fd<0)
    {
        perror("open");
        exit(1);
    }
    printf("fd=%d\n",fd);
    fflush(stdout);

    close(fd);
    exit(0);
}

来看看运行结果:
这里写图片描述

我们可以看到运行程序之后,多了一个我们创建的文件file,用cat命令查看文件的内容,发现本该输出到屏幕上的语句却写到了打开的文件里,而且文件描述符是1

FILE结构体

c语言的stdio.h头文件中,定义了用于文件操作的结构体FILE。因此我们通过fopen返回一个文件指针(指向FILE结构体的指针)来进行文件操作。文件指针指向进程的用户空间中的FILE结构体。
可以在stdio.h(位于visual studio安装目录下的include文件夹下)头文件中查看FILE结构体的定义,如下:
FILE结构体中最重要的两个成员变量是:文件描述符和缓冲区的大小

//C语言文件指针域文件描述符之间可以相互转换
int fileno(FILE * stream)
FILE * fdopen(int fd, const char * mode)

struct _iobuf {
    char *_ptr;          //文件输出的下一个位置
    int   _cnt;          //当前缓冲区的相对位置
    char *_base;         //缓冲区基址
    int   _flag;         //文件标志
    int   _file;         //文件描述符
    int   _charbuf;      //检查缓冲区状况,若无缓冲区则不读取
    int   _bufsiz;       //缓冲区大小
    char *_tmpfname;     //临时文件名 
};
typedef struct _iobuf FILE;

c程序用不同的FILE结构体管理每个文件。程序员可以使用文件,但是不需要知道FILE结构体的细节。实际上,FILE结构体是间接地操作系统的文件控制块(FCB)来实现对文件的操作的。
FILE结构体中的_file ,也就是文件描述符,作为进入打开文件表索引的整数。

文件描述符和FILE结构体的关系

在Linux下编程常需要对一些文件进行操作。有时不同的条件下,需要将文件指针即句柄(FILE*)、文件描述符(fd)以及文件路径(filepath)进行相互转换,以满足实际的编程需要。

  • 文件路径 文件描述符应是唯一的。文件指针(值)不是唯一的,但指向的对象也应该是唯一的
  • FILE* 中包含fd的信息,而且还包含IO缓冲,所以可以理解为 FILE* 是对fd的封装,是C的标准形式,所以FILE* 比fd更适合跨平台,应多用fopen,少用 open。

文件描述符 到 文件指针:fd–fdopen()–>FILE*
文件指针 到 文件描述符:FILE*–fileno()—>fd

### 文件描述符及 `FILE` 结构体的概念 #### 文件描述符 文件描述符是一个整数,用于标识操作系统中已打开的文件或 I/O 资源。它提供了一种抽象机制来处理各种类型的输入输出操作。在 Unix 和 Linux 系统中,每个进程都有自己的文件描述符表,其中包含了该进程中所有打开文件的信息。 #### `FILE` 结构体 `FILE` 是标准 C 库中的一个不透明数据类型,表示流(stream),通常用来封装底层的文件描述符和其他控制信息。通过 `FILE*` 指针可以方便地进行高级别的文件读写操作。要从 `FILE` 对象获得其对应的文件描述符,可使用 `fileno()` 函数[^1]。 ```c #include <stdio.h> int main() { FILE *fp; fp = fopen("example.txt", "r"); if (fp != NULL) { int fd = fileno(fp); printf("File descriptor of example.txt is %d\n", fd); fclose(fp); } } ``` ### 使用文件描述符的操作 对于低级别的 I/O 操作,可以直接利用文件描述符来进行更精细的控制。例如,在多线程或多进程编程时,可能需要管理多个并发连接;此时,使用文件描述符集合 (`fd_set`) 来跟踪哪些文件准备好读取或写入会更加高效。下面展示了如何清除特定文件描述符的状态: ```c #include <sys/select.h> #include <unistd.h> void clear_fd(int fd, fd_set *set) { FD_CLR(fd, set); // 将参数文件描述符fd对应标志设置为0 } ``` 此外,在某些情况下,还需要跨进程共享文件资源。这可以通过复制文件描述符或将整个 `struct file` 结构传递给另一个进程实现[^3]。 ### 相关 API 及宏定义 当涉及到不同平台上的兼容性问题时,可以根据编译环境条件编译相应的代码片段。比如针对 Windows 和 POSIX 平台的不同特性做出适配: ```cpp #ifdef _WIN32 #define EXPORT extern "C" __declspec(dllexport) #else // unix/linux #define EXPORT extern "C" #endif EXPORT void some_function() { // 实现细节... } ``` 上述例子展示了一个简单的导出函数声明方式,适用于创建动态链接库(DLL),使得其他程序能够调用此功能模块内的接口[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值