<分区>
我的理解是fopen()
和open()
都可以用来打开文件。 open()
返回一个文件描述符。但它们在获取用于写入或读取的文件方面应该是等效的。定义文件描述符的目的是什么?从 wiki 页面看不清楚。
<分区>
我的理解是fopen()
和open()
都可以用来打开文件。 open()
返回一个文件描述符。但它们在获取用于写入或读取的文件方面应该是等效的。定义文件描述符的目的是什么?从 wiki 页面看不清楚。
最佳答案
fopen
返回一个 FILE *
,它是文件描述符的包装器(我将在这里忽略“这不是规范所要求的”方面,就像我一样不知道不执行此操作的实现)。在高层次上,它看起来像这样:
application --FILE *--> libc --file descriptor--> kernel
Shell 直接对文件描述符进行操作,主要是因为它们正在执行其他程序,而您不能修改其他程序的FILE *
对象。但是,您可以在启动时使用 dup
系统调用(即在 fork
和 exec
之间)修改其他程序的文件描述符。例如:
/bin/cat > foo.txt
这告诉 shell 执行 /bin/cat
程序,但首先将 stdout(文件描述符 #1)重定向到它打开的文件。这是实现为(伪代码):
if (fork() == 0) {
int fd = open("foo.txt");
dup2(fd, 1);
exec("/bin/cat");
}
您可以使用 FILE *
做的最接近的事情是调用 freopen
,但与文件描述符不同,当使用 exec
时,这不会持久化。
但是,如果它只是一个文件描述符的包装器,那我们为什么还需要 FILE *
呢?一个主要的好处是有一个预读缓冲区。例如,考虑 fgets
。这最终将在与您传入的 FILE *
关联的文件描述符上调用 read
系统调用。但是它如何知道要读取多少?内核没有选择说“给我一行”(除了行缓冲的 ttys)。如果您在第一次read
中读取了多行,那么下次您调用fgets
时,您可能只会得到下一行的一部分,因为内核已经给了您前面的 read
系统调用的第一部分。另一种选择是一次调用 read
一个字符,这对性能来说很糟糕。
那么 libc 是做什么的呢?它一次读取一堆字符,然后将多余的字符存储在 FILE *
对象的内部缓冲区中。下次您调用 fgets
时,它就可以使用内部缓冲区。此缓冲区还与 fread
等函数共享,因此您可以交替调用 fgets
和 fread
而不会丢失数据。
关于c - 文件描述符的目的是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54565453/