“文件指针”,“流”,“文件描述符”和......“文件”之间的区别?

Posted

技术标签:

【中文标题】“文件指针”,“流”,“文件描述符”和......“文件”之间的区别?【英文标题】:Difference between "file pointer", "stream", "file descriptor" and ... "file"? 【发布时间】:2020-09-06 17:03:44 【问题描述】:

有一些相关的概念,即文件指针文件描述符。 我知道 文件指针 是指向数据类型 FILE 的指针(例如在 FILE.hstruct_FILE.h 中声明)。 我知道 文件描述符int,例如FILE 的成员 _fileno(和 _IO_FILE)。

至于the subtle difference between stream and file,我还在学习中。

但是从here,我不清楚是否还有另一种类型的实体适用于“文件状态标志”。 具体来说,我不知道“文件状态标志”是否适用于FILE文件描述符或什么。 我正在寻找显示具体细节的官方参考资料。

相关:

What's the difference between a file descriptor and file pointer?

Whats is difference between file descriptor and file pointer?

What is the concept behind file pointer or the stream pointer?

Specification of file descriptors(我问过这个)

difference between file descriptor and socket file descriptor

【问题讨论】:

这或多或少都是一样的conecpt。 FILE 指针、文件描述符、流、句柄等都只是一个抽象对象,允许您向/从先前打开的文件写入和/或读取信息。 FILE 结构的成员是不相关的并且是特定于实现的。你不想也不应该关心他们。 文件状态标志几乎肯定适用于本机文件系统的文件概念。 FILE 对象只需要维护一个错误指示符和一个EOF 指示符(通过ferrorfeof 库函数访问)。不知何故,本机状态标志被映射到这两个指标上。请注意,文件 描述符 和使用它们的函数不是标准 C 库的一部分,它们是 POSIX 特定的。 【参考方案1】:

文件句柄

当您第一次访问某个网站时,该网站可能会为您的浏览器提供一个 cookie。此 cookie 的值将在浏览器将来请求时自动提供给网站。

此 cookie 的值对您来说可能是胡言乱语,但它对特定的 Web 服务器有意义。它被称为会话ID,它是在某种数据库中查找记录的关键。此记录称为会话。

会话允许网络服务器根据较早的请求和较早请求的结果对一个请求作出反应。例如,它允许服务器知道浏览器在较早的请求中向服务器提供了凭据,并且这些凭据已成功验证。这就是为什么您每次想在 *** 上以特定用户的身份发布/投票/编辑时都不需要重新提供凭据。

cookie 的值,即会话 ID,是一个不透明的值。它对你没有任何意义。它有用的唯一方法是将其提供回给您的 Web 服务器。将其提供给另一个 Web 服务器不会有任何用处。它只是一种识别存在于另一个系统中的资源的方法。

当其他系统是操作系统时,我们将这些资源识别不透明值称为“句柄”。这绝不是唯一一次以这种方式使用单词句柄,但它是最常见的。就像会话 id cookie 为 Web 服务器提供一种将 Web 请求链接在一起的方式一样,句柄为操作系统提供了一种将系统调用链接在一起的方式。有各种资源的句柄。有窗把手。分配的内存缓冲区有句柄。还有文件句柄。

通过在对readwrite 的多次调用中使用相同的文件句柄,操作系统可以知道前一个在哪里停止,从而从哪里继续。它还知道您可以访问正在读取或写入的文件,因为这些检查是在文件打开时完成的。

文件句柄不仅仅用于普通文件。文件句柄还可以引用管道、套接字或许多其他事物之一。创建句柄后,您只需告诉操作系统您要从中读取或写入,它就会使用句柄来查找执行此操作所需的信息。


文件描述符

这是在 unix 世界中赋予文件句柄的名称。据说open(2) 返回一个文件描述符。据说read(2) 采用文件描述符。


FILE*又名FILE指针又名文件指针

这也是一个文件句柄。但与文件描述符不同的是,它不是来自操作系统。 FILE* 是 C 库文件句柄。您不能将FILE* 传递给read(2)(系统调用),就像您不能将文件描述符传递给fread(3)(C 库函数)一样。

你不应该访问FILE 的成员,假设它甚至有任何成员。像所有手柄一样,它对接收它的人来说是不透明的。它是一个你看不到的盒子。违反此约定的代码是不可移植的,并且可能随时中断。

大多数 C 库文件句柄都引用包含文件描述符的对象。 (fmemopenopen_memstream 返回的不返回。)它还包括对缓冲的支持,可能还有更多。


文件状态标志

这不是您永远需要使用的术语。这是我第一次听到它。或者也许我只是忘了听它,因为它并不重要。在链接的文档中,它用于引用一组常量。可以为某些参数提供该组中某些常量的某些组合的各种系统调用。请参阅每个系统的文档以查看它可以接受哪些标志,以及这些标志对它有什么意义。


串流

之前,我将文件句柄与会话 ID 进行了比较。如果会话 id 允许 Web 服务器查找会话,那么用于查找的文件句柄是什么? C 库 I/O 函数的文档将其称为流。

流是一个松散的术语,通常指的是不确定长度的序列。它是通信中常用的术语,指的是在编写者/发送者/生产者和阅读者/接收者/消费者之间进行通信的数据。

流是按顺序访问的,无论是出于必要还是方便。跳转到流中不同点的可能性不会自动取消该术语的使用资格。就像我上面提到的,这是一个宽松的术语。

流的长度通常是未知的。发件人甚至可能不知道它。举个例子,一个任务在运行中产生一个流,可能来自其他流。一条流甚至可以无限长。有时,流的长度是可知的,但被忽略了。有时,长度是已知的,但不是可用单位。从流中读取可变长度行的程序可能无法对流的长度(以字节为单位)做任何有用的操作。

让两个程序通过管道进行通信,如cat <file1 | cat >file2。我们可以将通过管道的数据称为流。发件人可能知道也可能不知道它最终会发送多少字节/行/消息。发送者将发送一些字节,然后再发送更多,直到它最终发出信号,不再有后续。读者通常不知道生产者最终会发送多少字节/行/消息。它会先获取一些字节,然后再获取更多,直到最终通知已到达流的末尾。

有时,更重要的是如何处理数据。例如,从文件中读取通常被视为从流中读取。虽然可以获得文件的长度,但通常会忽略此信息。相反,忽略此信息的程序只是不断从文件句柄中提取字节或行,直到它收到到达流末尾的指示。

随机访问是不将文件视为流的示例。随机访问是指从文件的任意位置检索数据的做法。当一个人有一个在文件中找到的索引时,可能会这样做。索引是键与文件中由该键标识的项目的位置之间的某种映射。例如,如果我知道在文件的某个位置找到与用户有关的数据,我可以从操作系统请求文件的该部分,而不是从一开始就读取文件。

【讨论】:

@thealchemist,谢谢。由于编辑冲突,您的更改被拒绝,但我会立即整合它们 @thealchemist,保留“web server”和“文件句柄”。 感谢您花时间写详细的解释。我会经历它然后回来。一个小细节:“文件状态标志”是我链接的页面中提到的一个概念,而且(至少)在the man page of fcntl 中也提到过,许多人在编写代码时可能需要它作为权威参考。所以我不会忽视它。 Re "一个小细节",但这正是我所说的!已经说过您应该检查各个函数的文档以查看接受哪些标志。链接的fcntl 文档准确列出了它接受并因此返回的标志,就像我说的那样。您的评论没有添加任何内容。 Re "一个小细节",但这正是我所说的!已经说过您应该检查各个函数的文档以查看接受哪些标志。链接的fcntl 文档准确列出了它接受并因此返回的标志,就像我说的那样。你注意到fcntl 只接受一些标志了吗?您的评论没有添加任何内容。

以上是关于“文件指针”,“流”,“文件描述符”和......“文件”之间的区别?的主要内容,如果未能解决你的问题,请参考以下文章

文件描述符与文件指针的关系与区别

Linux中文件描述符fd和文件指针flip的理解

文件描述符fd文件指针fp和vfork()

getline() 带有文件描述符而不是文件指针

如何将文件指针 ( FILE* fp ) 转换为文件描述符 (int fd)?

如何将文件描述符(int fd)转换为文件指针(FILE * fp)