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页面看不清楚
这两个功能在不同的级别:
是一个较低级别的POSIX函数,用于打开文件。它返回一个不同的整数,以标识打开的文件并启用对该文件的访问。这个整数是一个文件描述符open()
是一个更高级、可移植的C标准库函数,用于打开文件fopen()
fopen()
可能调用不可移植的open()
,但这是一个实现细节
如有疑问,请选择fopen()
有关详细信息,请在Linux系统上阅读
man 2
。POSIXread()
函数通过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");
}