与维基百科相比,文件描述符的简化描述是什么?他们为什么需要?比如说,以shell进程为例,它是如何应用的?
进程表是否包含多个文件描述符。如果是,为什么?
答案 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中,stdin
,stdout
和stderr
是FILE*
,在UNIX中分别映射到文件描述符0
,1
和{{ 1}}。
答案 2 :(得分:88)
从马口听到:APUE(Richard Stevens)。
对于内核,文件描述符引用所有打开的文件。文件描述符是非负数。
当我们打开现有文件或创建新文件时,内核会向进程返回一个文件描述符。内核维护一个正在使用的所有打开文件描述符的表。文件描述符的分配通常是顺序的,并且它们被分配给文件作为来自空闲文件描述符池的下一个空闲文件描述符。当我们关闭文件时,文件描述符被释放并可用于进一步分配 有关详细信息,请参阅此图片:
当我们想要读取或写入文件时,我们使用 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
的更多要点:
File Descriptor
(FD)是非负整数File Descriptors
,与打开的文件相关联。
(0, 1, 2, ...)
是标准的 FD ,对应0, 1, 2
,STDIN_FILENO
和STDOUT_FILENO
(在{中定义) {1}})在程序启动时默认代表shell打开。
FD按顺序分配,意味着可能的最低未分配整数值。
特定流程的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
轻松识别STDOUT
,STDERR
和lsof -p PID
的文件描述符,或者如果我们ls /proc/PID/fd
也可以看到相同的文件描述符
还请注意,内核跟踪的文件描述符表与文件表或inodes表不同。这些是分开的,如其他一些答案所解释。
您可能会问自己,这些文件描述符物理上在哪里以及例如/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操作系统一样,回想起定义了七种文件类型:
答案 6 :(得分:4)
文件描述符(FD):
$ 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)
答案 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 连接等。
答案 12 :(得分:-5)
文件描述符是文件的描述符。它们提供文件链接。在他们的帮助下,我们可以读取,写入和打开文件。