我的理解是fopen()
和open()
都可以用来打开文件。 open()
返回文件描述符。但是就获取用于写入或读取的文件而言,它们应该等效。定义文件描述符的目的是什么?从Wiki页面尚不清楚。
答案 0 :(得分:2)
fopen
返回一个FILE *
,它是文件描述符的包装器(我将忽略此处的“规范未要求的内容”,因为我不知道有一个实现不这样做)。从高层次看,它是这样的:
application --FILE *--> libc --file descriptor--> kernel
Shell直接在文件描述符上操作,主要是因为它们正在执行其他程序,并且您不能修改其他程序的FILE *
对象。但是,您可以在启动时使用dup
系统调用来修改其他程序的文件描述符(即,在fork
和exec
之间)。例如:
/bin/cat > foo.txt
这告诉外壳程序执行/bin/cat
程序,但首先将stdout(文件描述符#1)重定向到它打开的文件。这是通过(伪代码)实现的:
if (fork() == 0) {
int fd = open("foo.txt");
dup2(fd, 1);
exec("/bin/cat");
}
您可以使用FILE *
进行的最接近的操作是调用freopen
,但是与文件描述符不同,使用exec
时不会持久。
但是,如果它只是文件描述符的包装器,那为什么还需要FILE *
?一个主要好处是拥有预读缓冲区。例如,考虑fgets
。这最终将在与您传入的read
关联的文件描述符上调用FILE *
系统调用。但是它如何知道要读取多少内容?内核没有选择说“给我一行”(撇开行缓冲的ttys)。如果您在前read
的第一行中读了多行,那么下次调用fgets
时,您可能只会得到下一行的一部分,因为内核已经在上一个{ {1}}系统调用。另一种选择是一次调用read
一个字符,这对于性能来说是可怕的。
那么libc做什么?它一次读取一堆字符,然后将多余的字符存储在read
对象的内部缓冲区中。下次调用FILE *
时,它可以使用内部缓冲区。此缓冲区还与fgets
之类的功能共享,因此您可以交错调用fread
和fgets
而不丢失数据。
答案 1 :(得分:0)
这两个功能处于不同的级别:
open()
是用于打开文件的下层POSIX函数。它返回一个不同的整数以标识并允许访问打开的文件。该整数是文件描述符。 fopen()
是打开文件的高级可移植C标准库函数。在POSIX系统上,可移植的fopen()
可能会调用不可移植的open()
,但这是一个实现细节。
如有疑问,请选择fopen()
。
有关更多信息,在Linux系统上,man 2 read
。 POSIX read()
函数通过open()
返回的文件描述符读取数据。