3

我了解 C 中 ftell() 和 fseek() 的工作原理,但是对于这个问题,我在任何地方都找不到任何准确的答案,包括 StackOverflow( LINK ) 上最近的帖子。

那么您能否回答以下问题:

  • 是否可以断定 fgetpos() 和 fsetpos() 仅与以文本模式打开的文本文件相关,而与以二进制模式打开的文件无关?
  • 什么样的位置信息是由 fgetpos() 填充的 fpos_t 对象,假设它不是像 ftell() 给出的那样的长整数偏移量等?站点cplusplusreference仅告诉以下内容:

该函数用流位置指示符所需的信息填充 pos 指向的 fpos_t 对象,以将流恢复到其当前位置

4

3 回答 3

4

fgetpos()并且fsetpos()与文本和二进制模式相关。

的优点fgetpos()是保留了流中的完整位置,包括其内部状态,以便您可以稍后恢复。无论您是否处于文本模式,这都有效。如果您使用面向宽的流或在同一个文件中混合使用fgetc(),这一点尤其重要fgetwc(),因为某些语言环境使用状态相关的多字节编码(状态取决于先前的读取)。

fseek()并且ftell()还可以使用文本和二进制模式。然而,文本模式有一个重要的限制:你应该只使用fseek()0 或以前返回的值ftell()(在二进制模式下你可以使用你想要的任何值)。这是因为文本模式读取可以改变读取返回的字节数与文件中的有效字节数相比(典型示例,Windows 文件中的 2 个 CR+LF 字节被转换为一个符号 LF 字节)。

由于ftell()仅返回一个long int偏移量,因此如果需要,它无法跟踪多字节状态。所以使用fseek()可能会失去这种状态。

于 2015-10-24T13:22:38.713 回答
2

fgetpos除了其他答案中提到的原因之外,fsetpos如果您正在处理非常大的文件,则可能需要使用包含超过LONG_MAX字节的文件。LONG_MAX对于 2 31 − 1的系统,这是一个真正的问题;如今,包含超过 20 亿字节的文件并不少见。

如果您在实现 POSIX.1-2001 的系统上,有一个更好的选择,即#define _FILE_OFFSET_BITS 64在包含任何系统头文件之前,然后使用fseekoandftello . 这些就像fseekand一样,ftell只是它们接受/返回一个off_t数量,如果你做了上面的#define,保证是一个可以表示 2 63 - 1 的整数类型,这对任何人来说都应该足够了。这更好,因为您可以对off_t;进行算术运算。你不能fpos_t习惯去你没去过的地方。但是,如果您不在 POSIX 系统上,fgetpos并且fsetpos可能是您唯一的选择。

(请注意,某些系统会给你一个fpos_t不能表示大于LONG_MAX字节的文件偏移量。在其中一些系统上,应用相同的#define _FILE_OFFSET_BITS 64设置会有所帮助。在其他系统上,如果你想要一个大文件,你就完全不走运了.)

于 2018-03-06T02:13:28.997 回答
2

不完全的。可以从Beej找到线索:

在几乎每个系统(当然还有我所知道的每个系统)上,人们都不使用这些函数,而是使用 ftell() 和 fseek()。这些函数的存在是为了以防您的系统无法将文件位置记住为简单的字节偏移量。

Linux 手册页

在某些非 UNIX 系统上,fpos_t 对象可能是一个复杂对象,而这些例程可能是可移植地重新定位文本流的唯一方法。

Windows上:

它假定缓冲区中的任何 \n 字符最初都是一个 \r\n 序列,当数据被读入缓冲区时,该序列已被规范化。

也就是说,不是(Windows-linebreak)文本文件的文件在以文本模式打开时在 Windows 中出错,因为fsetpos假设该文件确实是(Windows-linebreak)文本文件,因此不能包含\n带有 no的 a \r

C11 标准说(我的重点):

7.21.2/6:

每个面向宽的流都有一个关联的 mbstate_t 对象,该对象存储流的当前解析状态。对 fgetpos 的成功调用会将此 mbstate_t 对象的值的表示存储为 fpos_t 对象的值的一部分。稍后使用相同存储的 fpos_t 值成功调用 fsetpos 会恢复关联的 mbstate_t 对象的值以及受控流中的位置。

请注意,fseek对对象ftell无话可说mbstate_t:他们不报告或恢复它。因此,在面向宽的流(也就是说,您使用面向宽的 I/O 函数的流)上,它们只会重置文件位置,而不是(如果实现实际上具有多个可能的mbstate_t对象值)流的整个状态。

面向宽的流与文本流不同,只是读取宽文本文件是它们的常见用途。实际上fseek并且ftell被记录为能够在文本文件上重置文件位置,前提是您正确使用它们。所以我相信(我可能错了),fsetpos并且fgetpos只有在流上使用宽 I/O 函数时才需要。

于 2015-10-24T13:24:57.910 回答