什么是文件描述符,用简单的术语解释?

时间:2011-03-10 07:17:22

标签: unix operating-system file-descriptor

  1. 与维基百科相比,文件描述符的简化描述是什么?他们为什么需要?比如说,以shell进程为例,它是如何应用的?

  2. 进程表是否包含多个文件描述符。如果是,为什么?

13 个答案:

答案 0 :(得分:479)

简单来说,当您打开文件时,操作系统会创建一个表示该文件的条目并存储有关该打开文件的信息。因此,如果您的操作系统中打开了100个文件,那么OS中将有100个条目(内核中的某个位置)。这些条目由整数表示,如(... 100,101,102 ....)。此条目号是文件描述符。 因此它只是一个整数,它唯一地表示操作系统中打开的文件。 如果您的进程打开10个文件,那么您的Process表将有10个文件描述符条目。

类似地,当您打开网络套接字时,它也由一个整数表示,它被称为套接字描述符。 我希望你明白。

答案 1 :(得分:98)

文件描述符是一个不透明的句柄,用于用户和内核空间之间的接口,以识别文件/套接字资源。因此,当您使用open()socket()(系统调用接口到内核)时,会给您一个文件描述符,它是一个整数(它实际上是进程结构的索引 - 但是这不重要)。因此,如果您想直接与内核接口,使用对read()write()close()等系统调用,您使用的句柄就是文件描述符。

系统调用上覆盖了一层抽象,即stdio接口。这提供了比基本系统调用更多的功能/特性。对于此接口,您获得的不透明句柄是FILE*,由fopen()调用返回。有许多功能使用stdio界面fprintf()fscanf()fclose(),这些功能可以让您的生活更轻松。在C中,stdinstdoutstderrFILE*,在UNIX中分别映射到文件描述符01和{{ 1}}。

答案 2 :(得分:88)

从马口听到:APUE(Richard Stevens)。
对于内核,文件描述符引用所有打开的文件。文件描述符是非负数。

当我们打开现有文件或创建新文件时,内核会向进程返回一个文件描述符。内核维护一个正在使用的所有打开文件描述符的表。文件描述符的分配通常是顺序的,并且它们被分配给文件作为来自空闲文件描述符池的下一个空闲文件描述符。当我们关闭文件时,文件描述符被释放并可用于进一步分配 有关详细信息,请参阅此图片:

Two Process

当我们想要读取或写入文件时,我们使用 open() create()函数调用返回的文件描述符来标识文件,并且将其用作 read() write()的参数。
按照惯例,UNIX系统shell将文件描述符0与进程的标准输入,文件描述符1与标准输出相关联,文件描述符2与相关联标准错误
文件描述符的范围从0到OPEN_MAX。可以使用ulimit -n获取文件描述符最大值。有关更多信息,请参阅APUE Book的第3章。

答案 3 :(得分:14)

作为其他答案的补充,unix将所有内容视为文件系统。键盘是一个只从内核角度读取的文件。该屏幕是只写文件。类似地,文件夹,输入输出设备等也被认为是文件。每当打开文件时,例如当设备驱动程序[用于设备文件]请求open(),或者进程打开用户文件时,内核就会分配一个文件描述符,这是一个整数,指定对该文件的访问权限,使其只读,只写等[供参考:https://en.wikipedia.org/wiki/Everything_is_a_file]

答案 4 :(得分:14)

有关null的更多要点:

  1. File Descriptor(FD)是非负整数File Descriptors,与打开的文件相关联。

  2. (0, 1, 2, ...)是标准的 FD ,对应0, 1, 2STDIN_FILENOSTDOUT_FILENO(在{中定义) {1}})在程序启动时默认代表shell打开。

  3. FD按顺序分配,意味着可能的最低未分配整数值。

  4. 特定流程的FD可以在STDERR_FILENO中看到(在基于Unix的系统上)。

答案 5 :(得分:11)

其他答案增加了很多东西。我只加我的2美分。

根据Wikipedia,我们可以确定:文件描述符是一个非负整数。我认为最重要的事情是丢失:

文件描述符绑定到进程ID。

我们知道最著名的文件描述符是0、1和2。 0对应STDIN,1对应STDOUT,2对应STDERR

  

说,以shell进程为例,它如何应用?

查看此代码

#>sleep 1000 &
[12] 14726

我们创建了一个ID为14726(PID)的进程。 使用lsof -p 14726,我们可以得到如下信息:

COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
sleep   14726 root  cwd    DIR    8,1     4096 1201140 /home/x
sleep   14726 root  rtd    DIR    8,1     4096       2 /
sleep   14726 root  txt    REG    8,1    35000  786587 /bin/sleep
sleep   14726 root  mem    REG    8,1 11864720 1186503 /usr/lib/locale/locale-archive
sleep   14726 root  mem    REG    8,1  2030544  137184 /lib/x86_64-linux-gnu/libc-2.27.so
sleep   14726 root  mem    REG    8,1   170960  137156 /lib/x86_64-linux-gnu/ld-2.27.so
sleep   14726 root    0u   CHR  136,6      0t0       9 /dev/pts/6
sleep   14726 root    1u   CHR  136,6      0t0       9 /dev/pts/6
sleep   14726 root    2u   CHR  136,6      0t0       9 /dev/pts/6

第四列FD和第二列TYPE对应于文件描述符和文件描述符类型。

FD的某些值可以是:

cwd – Current Working Directory
txt – Text file
mem – Memory mapped file
mmap – Memory mapped device

但是实际文件描述符在以下位置:

NUMBER – Represent the actual file descriptor. 

数字即“ 1u”后的字符代表打开文件的模式。 r代表读取,w代表写入,u代表读写。

TYPE指定文件的类型。某些类型的值是:

REG – Regular File
DIR – Directory
FIFO – First In First Out

但是所有文件描述符都是     CHR –字符特殊文件(或字符设备文件)

现在,我们可以通过STDIN轻松识别STDOUTSTDERRlsof -p PID的文件描述符,或者如果我们ls /proc/PID/fd也可以看到相同的文件描述符

还请注意,内核跟踪的文件描述符表与文件表或inodes表不同。这些是分开的,如其他一些答案所解释。

fd table

您可能会问自己,这些文件描述符物理上在哪里以及例如/dev/pts/6中存储了什么

sleep   14726 root    0u   CHR  136,6      0t0       9 /dev/pts/6
sleep   14726 root    1u   CHR  136,6      0t0       9 /dev/pts/6
sleep   14726 root    2u   CHR  136,6      0t0       9 /dev/pts/6

嗯,/dev/pts/6完全生活在内存中。这些不是常规文件,而是所谓的字符设备文件。您可以使用以下命令进行检查:ls -l /dev/pts/6,它们将以c开头,在我的情况下为crw--w----

就像大多数Linux操作系统一样,回想起定义了七种文件类型:

  • 常规文件
  • 目录
  • 字符设备文件
  • 阻止设备文件
  • 本地域套接字
  • 命名管道(FIFO)和
  • 符号链接

答案 6 :(得分:4)

文件描述符(FD):

  • Linux / Unix 中,所有内容都是文件。常规文件,目录, 甚至设备都是文件。每个文件都有一个关联的编号,称为文件描述符(FD)。
  • 您的屏幕上还有一个文件描述符。执行程序时 输出被发送到屏幕的文件描述符,您将看到 显示器上的程序输出。如果输出发送到文件 打印机的描述符,程序输出将是 印刷。

    错误重定向:
    每当您在终端上执行程序/命令时,始终会打开3个文件
    1. 标准输入
    2. 标准输出
    3. 标准错误。

    每当运行程序时,这些文件始终存在。如前所述,文件描述符与每个 这些文件。
    文件 文件描述符
    标准输入STDIN 0
    标准输出STDOUT 1
    标准错误STDERR 2

  • 例如,在搜索文件时,一个 通常会出现权限被拒绝错误或其他某种错误。这些错误可以保存到特定文件。
    示例1
  

$ ls mydir 2> errorsfile.txt

标准错误的文件描述符为2。
如果没有名为mydir的目录,则命令的输出将保存到文件errorfile.txt
中。 使用“ 2>”将错误输出重定向到名为“ errorfile.txt”的文件。
因此,程序输出不会出现错误。

希望你能得到答案。

答案 7 :(得分:3)

任何操作系统都有进程(p' s)正在运行,例如 p1,p2,p3 等等。每个流程通常会持续使用文件。

每个流程都由流程树(或流程表,另一个措辞)组成。

通常,操作系统用数字(也就是说,在每个进程树/表中)代表每个进程中的每个文件

此过程中使用的第一个文件是 file0 ,第二个是 file1 ,第三个是 file2 ,依此类推。

任何此类号码都是文件描述符。

文件描述符通常是整数(0,1,2而不是0.5,1.5,2.5)。

鉴于我们经常将流程描述为"流程表",并且假设表有行(条目),我们可以说每个条目中的文件描述符单元用于表示整个条目。

以类似的方式,当您打开网络套接字时,它有一个套接字描述符。

在某些操作系统中,您可能会用完文件描述符,但这种情况极为罕见,普通计算机用户不应该担心。

文件描述符可能是全局的(进程A从0开始,结尾说1;进程B开始说2,结束说3)等等,但据我所知,通常在现代操作中系统,文件描述符不是全局的,并且实际上是特定于进程的(进程A从0开始,结束在5中,而进程B从0开始,结束在10中)。

答案 8 :(得分:2)

文件描述符

        
  • 要内核,所有打开的文件都由文件描述符引用。
  •     
  • 文件描述符是非负整数。
  •     
  • 当我们打开现有文件或创建新文件时,内核将文件描述符返回到进程。
  •     
  • 当我们想读取或写入文件时,我们将带有文件描述符的文件标识为通过open或create重新调整的文件,作为读取或写入的参数。     
  •     
  • 每个UNIX进程都有20个文件描述符,并对其进行处理,编号为0到19,但是     许多系统将其扩展到63。
  •     
  •     流程开始时,前三个已经打开        0:标准输入        1:标准输出        2:标准错误输出     
  •     
  • 当父进程派生一个进程时,子进程将继承父进程的文件描述符

答案 9 :(得分:1)

文件描述符不过是任何开放资源的引用。一旦打开资源,内核就会假设您将对其进行一些操作。通过程序和资源进行的所有通信都通过一个接口进行,并且该接口由文件描述符提供。

由于一个进程可以打开多个资源,因此一个资源可能具有多个文件描述符。
您只需运行即可查看链接到该流程的所有文件描述符, ls -li /proc/<pid>/fd/这里的pid是您进程的进程ID

答案 10 :(得分:0)

首先是所有简化的响应。
如果要在bash脚本中处理文件,最好使用文件描述符。
例如:-
您要读取和写入文件“ test.txt”。
使用文件描述符,如下所示

FILE=$1 # give the name of file in the command line
exec 5<>$FILE # '5' here act as the file descriptor
# Reading from the file line by line using file descriptor
while read LINE; do
    echo "$LINE"
done <&5

# Writing to the file using descriptor
echo "Adding the date: `date`" >&5 
exec 5<&- # Closing a file descriptor

答案 11 :(得分:0)

我不知道内核代码,但我会在这里加上我的两分钱,因为我已经考虑了一段时间,我认为它会很有用。

当您打开一个文件时,内核会返回一个文件描述符以与该文件进行交互。

文件描述符是您打开的文件的 API 实现。内核创建此文件描述符,将其存储在一个数组中,然后将其提供给您。

例如,此 API 需要一个允许您读取和写入文件的实现。

现在,再想想我说过的话,记住一切都是文件——打印机、显示器、HTTP 连接等。

这是我阅读https://www.bottomupcs.com/file_descriptors.xhtml后的总结。

答案 12 :(得分:-5)

文件描述符是文件的描述符。它们提供文件链接。在他们的帮助下,我们可以读取,写入和打开文件。