Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 文件描述符的用途是什么?_C_Fopen_File Descriptor - Fatal编程技术网

C 文件描述符的用途是什么?

C 文件描述符的用途是什么?,c,fopen,file-descriptor,C,Fopen,File Descriptor,我的理解是fopen()和open()都可以用来打开文件open()返回文件描述符。但在获取文件以供写入或读取方面,它们应该是等效的。定义文件描述符的目的是什么?从wiki页面看不清楚 这两个功能在不同的级别: open()是一个较低级别的POSIX函数,用于打开文件。它返回一个不同的整数,以标识打开的文件并启用对该文件的访问。这个整数是一个文件描述符 fopen()是一个更高级、可移植的C标准库函数,用于打开文件 在POSIX系统上,可移植的fopen()可能调用不可移植的open(),但

我的理解是
fopen()
open()
都可以用来打开文件
open()
返回文件描述符。但在获取文件以供写入或读取方面,它们应该是等效的。定义文件描述符的目的是什么?从wiki页面看不清楚


这两个功能在不同的级别:

  • open()
    是一个较低级别的POSIX函数,用于打开文件。它返回一个不同的整数,以标识打开的文件并启用对该文件的访问。这个整数是一个文件描述符
  • fopen()
    是一个更高级、可移植的C标准库函数,用于打开文件
在POSIX系统上,可移植的
fopen()
可能调用不可移植的
open()
,但这是一个实现细节

如有疑问,请选择
fopen()


有关详细信息,请在Linux系统上阅读
man 2
。POSIX
read()
函数通过
open()
返回的文件描述符读取数据,fopen返回一个
文件*
,它是文件描述符的包装器(我将忽略这里的“这不是规范所要求的”方面,因为我不知道有一个实现不这样做)。在高层次上,它看起来是这样的:

application --FILE *--> libc --file descriptor--> kernel
shell直接对文件描述符进行操作,主要是因为它们正在执行其他程序,并且您无法修改其他程序的
文件*
对象。但是,您可以在启动时使用
dup
系统调用(即在
fork
exec
之间)修改其他程序的文件描述符。例如:

/bin/cat > foo.txt
这告诉shell执行
/bin/cat
程序,但首先将stdout(文件描述符#1)重定向到它打开的文件。这实现为(伪代码):

使用
FILE*
可以做的最接近的事情是调用
freopen
,但与文件描述符不同,在使用
exec
时,这不会持久化

但是,如果它只是一个文件描述符的包装器,那么为什么我们需要
文件*
?一个主要好处是具有预读缓冲区。例如,考虑<代码> FGES。这将最终调用与传入的
文件*
关联的文件描述符上的
读取
系统调用。但它怎么知道要读多少呢?内核没有说“给我一行”的选项(除了行缓冲的TTY)。如果在第一个
read
中读取了多行,那么下次调用
fgets
时,您可能只会获得下一行的一部分,因为内核已经在上一个
read
系统调用中为您提供了第一部分。另一个选项是一次调用
read
一个字符,这对性能很糟糕


那么libc做什么呢?它一次读取一组字符,然后将多余的字符存储在
文件*
对象的内部缓冲区中。下次调用
fgets
时,它可以使用内部缓冲区。此缓冲区还与
fread
等函数共享,因此您可以交错调用
fgets
fread
,而不会丢失数据。

shell主要使用文件描述符。他们是如何使其可移植的?据我所知,如果系统支持基于POSIX的shell,比如Bash,并且据我所知,除了微软Windows以外的所有东西都支持它,也许现在Windows也支持它,那么系统将支持POSIX。因此,
open()。但是,从作为库的一部分的意义上讲,它是不可移植的,每个标准托管的C安装都需要提供。这是否回答了您的问题?可以通过C标准库的
fread()
fwrite()
函数(使用从
fopen()
获得的
文件*
)进行二进制I/O。另外,如果需要,您可以通过这种方式自动获得缓冲I/O。你能更具体地解释一下为什么你说基于文件描述符的I/O比流I/O更好地完成这些任务吗?@JohnBollinger你教了我一些我不知道的东西。为此,我使用
open()
已有20年了。考虑到你的建议,我删除了关于二进制和
fopen()
的段落。大部分是正确的,尽管
文件不一定要缓冲。但这些都不能真正回答所提出的问题。POSIX可以用(指向)
file
对象的指针来定义与文件描述符相关的大部分内容。观察到它没有,并不能解释为什么它没有。
if (fork() == 0) {
    int fd = open("foo.txt");
    dup2(fd, 1);
    exec("/bin/cat");
}