文件描述符与文件句柄

在我们日常编程中经常会遇到文件描述符(file descriptor)和文件句柄(file handler)这两个概念,特别是需要开发跨平台(跨windows和linux)项目的时候会被这两个概念搞得很头痛,所以下面来说说它们是什么东西及它们的区别与联系。

文件描述符

本质是一个索引号(非负整数),系统用户层可以根据它找到系统内核层的文件数据。这是一个POSIX标准下的概念,常见于类Unix系统,比如linux。windows也是声称遵循POSIX标准的,所以windows也有文件描述符这个概念,但不常用。

文件句柄

Windows下的概念。句柄是Windows下各种对象的标识符,比如文件(也许叫文档比较合适一点)、资源、菜单、光标、位图等。文件句柄和文件描述符类似,它也是一个非负整数,也用于定位文件数据在内存中的位置。


由于linux下所有东西都被看成是文件,比如文件(也许叫文档比较合适一点)、目录、进程、网络socket、各种硬件设备等,所以linux下的文件描述符其实就相当于windows下的句柄。文件句柄只是windows众多句柄中的一种类型而已。


下面用一张图来说明文件描述符的作用(windows下的句柄也是类似的,只是实现细节不同):
文件描述符

对上图进行说明之前,还要普及一个知识:一个操作系统对象(比如文件)在内存中的位置是不固定的。它有可能会在虚拟内存和物理内存中来回切换。

  • 由于一个文件在内存中的位置是会变的,而文件管理是系统内核的事,那么对于用户程序来说,要怎么定位它呢?这就是上面那张图要说明的。
  • 这里有三张表:进程文件表,文件概要表和文件节点表。其中进程文件表是每个进程都会有一张,而文件概要表和文件节点表是整个系统各有且只有一张。
  • 文件节点表中每一项数据就是文件的实际数据。
  • 文件概要表中的每一顼是文件的概要数据,它包含了文件的状态、当前文件读写位置、节点指针等。当文件节点表中的数据发生变化时(比如说位置变了),内核会相应地修改文件概要表中对应项的节点指针,让它指向最新的文件数据。
  • 进程文件表里记录了该进程打开的所有文件的文件描述符,看图可以知道文件描述符其实只是一个数组的下标,根据它可以访问数组的数据,而这个数组的数据就是指向该文件对应的文件概要表。
  • 所以,不管文件数据在内存中的哪个位置,只要我们有文件描述符,我们就可以找到该文件的概要数据,从而找到文件的数据来进行操作。

一些补充说明

  • 每个进程创建的时候都会打开三个文件:stdin,stdout和stderr。它们的文件描述符对应为0,1,2。
  • 系统分配文件描述符时总是分配最小可用的值。如果当前进程只使用了0,1,2这三个文件描述符,那下次分配的将是3。如果当前进程只使用了0,1,2,3,5这五个文件描述符,那下次分配的将是4。
  • 不同的文件概要中的节点指针可以指向同一个文件节点,另外,文件描述符与文件概要是一一对应的,因此,不同的文件描述符可以对应相同的文件结点,即同一个文件可以在同一时间内被多次打开,每次打开都会分配一个文件描述符及生成一个文件概要。
  • Windows一般不直接使用文件描述符,所以它提供了一个系统函数叫_get_osfhandle,它可以根据一个文件描述符来获得文件句柄。
  • Windows创建一个文件一定会生成一个文件句柄,但并不一定分配一个文件描述符,如果你需要一个文件描述符,可以使用_open_osfhandle来分配一个。
  • 在windows下不要混用文件描述符与文件句柄,最好就不要用文件描述符了。比如socket这个函数,它在linux下的返回值是一个文件描述符,而在windows下返回的是一个句柄,如果要写跨平台的代码,就得十分小心这些差异。
<think>好的,用户问的是文件句柄文件描述符是什么。首先,我需要确定这两个术语的定义以及它们之间的关系。在操作系统中,文件描述符(File Descriptor)是一个常见的概念,特别是在Unix/Linux系统中。而文件句柄(File Handle)可能在Windows或其他上下文中使用,但有时这两个术语会被混用,需要区分清楚。 用户可能对这两个概念有混淆,或者想了解它们的区别联系。我需要先明确各自的定义,再比较它们的异同。首先,文件描述符是Unix/Linux中的概念,是一个非负整数,用于标识打开的文件或I/O资源。而文件句柄在Windows中更常用,通常是一个指针或结构体,指向系统内部的文件对象。 接下来,要考虑用户的使用场景。用户可能是在学习操作系统、编程,或者在开发中遇到相关问题,比如处理文件I/O时的资源管理问题。需要解释清楚两者的底层机制,比如文件描述符是索引,而句柄可能更抽象。此外,需要提到编程中的实际应用,比如在C语言中使用open()返回文件描述符,在Windows中使用CreateFile返回句柄。 用户可能存在的深层需求是理解如何在不同系统中管理文件资源,或者调试文件相关的错误,比如“too many open files”这样的问题。因此,需要解释文件描述符的限制以及如何查看修改这些限制。同时,对比不同操作系统中的实现差异,帮助用户跨平台开发时避免混淆。 另外,需要检查是否有常见的误解。例如,有时人们会认为文件描述符文件句柄是完全不同的东西,但实际上它们都服务于同一目的,只是实现方式不同。因此,强调它们在功能上的相似性实现上的区别是有必要的。 最后,总结两者的关键点,确保用户能够清晰区分正确使用这两个术语。可能还需要提供示例代码或命令,如使用ulimit查看文件描述符限制,或者在程序中处理文件描述符的方法,以增强实用性。</think>### 文件句柄(File Handle)文件描述符(File Descriptor)的分步解析 --- #### **1. 核心概念** - **文件描述符(File Descriptor, FD)** - **定义**:在类Unix系统(Linux/macOS等)中,文件描述符是一个非负整数,用于唯一标识操作系统内核中打开的文件、管道、套接字等I/O资源。 - **本质**:是内核维护的「文件描述符表」的索引值。 - **范围**:通常从`0`开始分配,默认上限可通过`ulimit -n`查看(例如1024)。 - **文件句柄(File Handle)** - **定义**:在Windows系统中,文件句柄是一个指向系统内部文件对象的结构体指针(类似`HANDLE`类型)。 - **本质**:是操作系统对资源的抽象引用,不直接暴露底层细节。 --- #### **2. 功能对比** | 特性 | 文件描述符(Unix/Linux) | 文件句柄(Windows) | |--------------------|-------------------------|---------------------| | **标识方式** | 整数(如`3`) | 指针(如`0x00007FF`) | | **资源管理** | 通过`open()`/`close()` | 通过`CreateFile()`/`CloseHandle()` | | **标准输入/输出** | `0`=stdin, `1`=stdout, `2`=stderr | 独立API(如`GetStdHandle()`) | | **错误表示** | 返回`-1`(如`open()`失败) | 返回`INVALID_HANDLE_VALUE` | --- #### **3. 技术实现差异** - **Unix/Linux文件描述符** ```c int fd = open("file.txt", O_RDONLY); // 返回整数fd(如3) read(fd, buffer, size); close(fd); ``` - **内核结构**:每个进程的`task_struct`包含`files_struct`结构,其中`fd_array`数组保存打开的文件指针。 - **Windows文件句柄** ```c HANDLE hFile = CreateFile("file.txt", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); ReadFile(hFile, buffer, size, &bytesRead, NULL); CloseHandle(hFile); ``` - **内核对象**:句柄指向`_FILE_OBJECT`结构,包含文件位置、访问模式等元数据。 --- #### **4. 常见问题调试** - **资源泄漏** - **Unix**:未关闭的文件描述符可通过`lsof -p <PID>`查看。 - **Windows**:未释放的句柄可通过Process Explorer工具检测。 - **限制调整** - **Unix文件描述符上限**: ```bash ulimit -n 4096 # 临时修改 # 永久修改需编辑/etc/security/limits.conf ``` - **Windows句柄上限**:由系统内存动态管理,无固定限制。 --- #### **5. 跨平台编程注意事项** - **代码示例(兼容性处理)** ```c #ifdef __linux__ int fd = open("file", O_RDWR); #elif _WIN32 HANDLE hFile = CreateFile("file", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); #endif ``` - **错误处理差异** - Unix:检查`errno`(如`EACCES`权限错误) - Windows:调用`GetLastError()`获取错误码(如`ERROR_ACCESS_DENIED`) --- ### 总结 - **文件描述符**是Unix/Linux对I/O资源的轻量级整数标识,**文件句柄**是Windows对资源的抽象指针。 - **核心区别**:前者直接映射内核数据结构,后者通过API间接操作。 - **共同目标**:提供对文件、网络等资源的统一访问接口。 是否需要进一步了解文件I/O性能优化或特定编程语言(如Python/Java)中的封装实现?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值