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

问题描述 投票:312回答:11
  1. 与维基百科相比,文件描述符的简化描述是什么?他们为什么需要?比如说,以shell进程为例,它是如何应用的?
  2. 进程表是否包含多个文件描述符。如果是,为什么?
unix operating-system file-descriptor
11个回答
487
投票

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

-5
投票

文件描述符是文件的描述符。它们提供了一个文件的链接。借助它们,我们可以读取,写入和打开文件。


98
投票

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

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


88
投票

从马的嘴里听到它:APUE(理查德史蒂文斯)。 对于内核,文件描述符引用所有打开的文件。文件描述符是非负数。

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

Two Process

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


16
投票

关于File Descriptor的更多观点:

  1. File Descriptors(FD)是非负整数(0, 1, 2, ...),它们与打开的文件相关联。
  2. 0, 1, 2是标准FD,对应于STDIN_FILENOSTDOUT_FILENOSTDERR_FILENO(在unistd.h中定义)默认代表shell在程序启动时打开。
  3. FD按顺序分配,意味着可能的最低未分配整数值。
  4. 可以在/proc/$pid/fd(基于Unix的系统)中看到特定过程的FD。

14
投票

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


12
投票

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

根据维基百科,我们肯定知道:文件描述符是一个非负整数。我认为最重要的缺失就是:

文件描述符绑定到进程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

第4列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指定文件的类型。 TYPE的一些值是:

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

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

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

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

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)和
  • 符号链接

4
投票

文件描述符(FD):

  • 在Linux / Unix中,一切都是文件。常规文件,目录,甚至设备都是文件。每个文件都有一个名为文件描述符(FD)的关联编号。
  • 您的屏幕还有一个文件描述符。执行程序时,输出将被发送到屏幕的文件描述符,您可以在显示器上看到程序输出。如果输出发送到打印机的文件描述符,则程序输出将被打印。 错误重定向: 无论何时在终端上执行程序/命令,都会打开3个文件 标准输入 标准输出 标准错误。 运行程序时,这些文件始终存在。如前所述,文件描述符与这些文件中的每一个相关联。 文件文件描述符 标准输入STDIN 0 标准输出STDOUT 1 标准错误STDERR 2
  • 例如,在搜索文件时,通常会获得权限拒绝错误或其他一些错误。这些错误可以保存到特定文件中。 例1

$ ls mydir 2> errorsfile.txt

标准错误的文件描述符是2。 如果没有任何名为mydir的目录,则命令输出将保存到文件errorfile.txt 使用“2>”我们将错误输出重定向到名为“errorfile.txt”的文件 因此,程序输出不会出错。 我希望你得到你的答案。


3
投票

任何操作系统都有进程(p)运行,比如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中)。


2
投票

File descriptors

  • 对于内核,所有打开的文件都由文件描述符引用。
  • 文件描述符是非负整数。
  • 当我们打开现有文件或创建新文件时,内核会将文件描述符返回给进程。
  • 当我们想要读取或写入文件时,我们使用open或create返回的文件描述符标识文件,作为读取或写入的参数。
  • 每个UNIX进程都有20个文件描述符并进行处理,编号为0到19,但许多系统将其扩展为63。
  • 当过程开始时,前三个已经打开0:标准输入1:标准输出2:标准错误输出
  • 当父进程分叉进程时,子进程继承父进程的文件描述符
© www.soinside.com 2019 - 2024. All rights reserved.