文件描述符及文件指针

本文详细介绍了Linux系统中的文件描述符与C语言中的文件指针的概念,并解释了它们之间的区别与联系。同时,还深入探讨了FILE结构体的具体组成,以及如何通过fdopen和fileno函数实现两者的转换。

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

文件描述符:在linux系统中打开文件就会获得文件描述符,它是个很小的正整数。每个进程在PCB(ProcessControl Block)中保存着一份文件描述符表,文件描述符就是这个表的索引,每个表项都有一个指向已打开文件的指针。

文件指针:C语言中使用文件指针做为I/O的句柄。文件指针指向进程用户区中的一个被称为FILE结构的数据结构。FILE结构包括一个缓冲区和一个文件描述符。而文件描述符是文件描述符表的一个索引,因此从某种意义上说文件指针就是句柄的句柄(在Windows系统上,文件描述符被称作文件句柄)。

         在/usr/include下的文件里我们可以找到FILE结构体的定义(以Centos 6.4 为例,不同系统有差异):

stdio.h

typedef struct _IO_FILE __FILE;

用grep –Rnw _IO_FILE 查找,可知_IO_FILE定义于libio.h

libio.h

struct _IO_FILE {
  int_flags;          /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags
 
  /* The following pointers correspond to the C++ streambufprotocol. */
  /*Note:  Tk uses the _IO_read_ptr and_IO_read_end fields directly. */
 char* _IO_read_ptr;   /* Currentread pointer */
 char* _IO_read_end;   /* End ofget area. */
 char* _IO_read_base;  /* Start ofputback+get area. */
  char* _IO_write_base; /* Start of put area. */
 char* _IO_write_ptr;  /* Currentput pointer. */
 char* _IO_write_end;  /* End ofput area. */
 char* _IO_buf_base;   /* Start ofreserve area. */
 char* _IO_buf_end;    /* End ofreserve area. */
  /*The following fields are used to support backing up and undo. */
 char *_IO_save_base; /* Pointer to start of non-current get area. */
 char *_IO_backup_base;  /* Pointerto first valid character of backup area */
 char *_IO_save_end; /* Pointer to end of non-current get area. */
 
 struct _IO_marker *_markers;
 
 struct _IO_FILE *_chain;
 
  int_fileno;
#if 0
  int_blksize;
#else
  int_flags2;
#endif
 _IO_off_t _old_offset; /* This used to be _offset but it's toosmall.  */
 
#define __HAVE_COLUMN /* temporary */
  /*1+column number of pbase(); 0 is unknown. */
 unsigned short _cur_column;
 signed char _vtable_offset;
 char _shortbuf[1];
 
 /*  char* _save_gptr;  char* _save_egptr; */
 
 _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

        从FILE数据结构我们可以看出:struct FILE中包含文件状态(flag),对应的文件描述符(_fileno),及很多和流缓冲区相关的操作指针。故文件指针与文件描述符是1对1 的关系,两者可以相互转换。其转换可利用以下函数:

从描述符获取文件指针:fdopen

从指针获取文件描述符:fileno

附:

文件描述符和内核file数据结构

    每个进程在PCB(ProcessControl Block)中都保存着一份文件描述符表,文件描述符就是这个表的索引,每个表项都有一个指向已打开文件的指针。即当打开一个文件时,内核会为已打开的文件创建一个file 结构体,文件描述符表中的指针指向file结构体。以下是一些常用场景下两者的关系:

1、  打开同一个文件,可能其file结构体不一样,这点可以从file结构体中存放了文件状态(读写权限等),文件偏移量,和文件目录项等数据不一样来理解。

2、  可使用dup,fork等函数进行文件描述符复制,这时会导致多个文件描述符指向同一个file结构体,其file数据结构的引用计数+1

3、  当调用close关闭文件时,file结构体中对应的文件引用计数-1,当计数达到0时才真正关闭文件。

p.s:内核中的file结构与FILE结构又是两个不同的概念。

参考链接:

http://blog.chinaunix.net/uid-20672257-id-1901040.html

想理解内核文件系统的话可以看下,文章写得很好

### 文件描述符文件指针的区别与联系 #### 一、基本概念 文件描述符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 接口实例。 --- ### 总结 综上所述,文件描述符文件指针各有优劣之处:前者更加贴近硬件本质且效率较高但灵活性较差;后者虽牺牲了一些性能却极大地简化了复杂场景下的编码工作量并且增强了安全性保障措施。根据项目需求合理选用合适的工具才是最重要的原则之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值