fgetpos/fsetpos 和 ftell/fseek 有啥区别

Posted

技术标签:

【中文标题】fgetpos/fsetpos 和 ftell/fseek 有啥区别【英文标题】:what is difference between fgetpos/fsetpos and ftell/fseekfgetpos/fsetpos 和 ftell/fseek 有什么区别 【发布时间】:2010-07-27 22:49:25 【问题描述】:

使用函数fgetpos()fsetpos() 与使用函数ftell()fseek() 在文件中获取和设置位置有什么区别?

fgetpos()fsetpos() 有什么用?为什么要使用它们而不是 ftell()fseek()

【问题讨论】:

见***.com/questions/12119132/… 它的答案比这里接受的答案要好。 【参考方案1】:

以上答案均不正确 - 事实上,如果您将 fsetposfseek 互换使用,您可能会引入安全漏洞 (https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=20087255)。

原因是fsetposfpos_t *pos 参数实际上不是整数,因此它不能用于查找文件中的任意位置。因此,唯一有效的值是从fgetpos 获得的值。正如文档所说,

与流相关的内部文件位置指示符设置为pos 表示的位置,它是一个指向fpos_t 对象的指针其值应先前已通过调用fgetpos 获得。

(http://www.cplusplus.com/reference/cstdio/fsetpos/)

如果您想要的只是寻找超出 32 位边界的任意位置的能力,请使用 ftello / fseeko 并使用 #define _FILE_OFFSET_BITS 64 进行编译。

【讨论】:

实际上并不是这个问题的确切答案,但作为提示非常好!谢谢! @likern 这正是问题的答案。而且它也是正确的答案,接受的答案是绝对不正确的,因为fpos_t 可能根本不是整数(标准不要求它是)。 ftellofseeko 是 POSIX 函数。此外,C11 标准在 7.21.9.1 中声明:“fgetpos 函数存储解析状态的当前值(如果有)和 pos 指向的对象中 stream 指向的流的文件位置指示符”此外:在 7.21 中。 1 声明:“fpos_t 这是一个完整的对象类型,而不是能够记录唯一指定文件中每个位置所需的所有信息的数组类型”但是,至少在我的系统上fpos_t 是@987654339 @ 原来是__int64_t。可能时使用 fsetpos 和 fgetpos 我无法打开链接:/推理的任何副本? 我不会说这是错误的,因为我不知道,但每次我从 Confluence 就潜在的 C 安全风险提出建议时,他们都错了。【参考方案2】:

好吧,从手册页我们可以看到 ftell 和 fseek 使用类型 long int 来表示文件中的偏移量(位置),因此可能仅限于可以用 long int 表示的偏移量。 (不保证 long int 类型保留大于 2**31-1 的值,将最大偏移量限制为 2 GB)。另一方面,较新的 fgetpos 和 fsetpos 函数使用特殊的 typedef fpos_t 来表示偏移量。如果选择得当,这个 typedef 后面的类型可以表示任意大的偏移量,因此 fgetpos 和 fsetpos 可以用于任意大的文件。 fgetpos 和 fsetpos 还记录与多字节流相关的状态。

【讨论】:

这个答案是错误的!如果你只是想超越2**31-1,那么fseeko。正确的答案是 fgetpos 只能寻找先前由 fgetpos 获得的位置,并且 fpos_t 绝不能被解释为整数,正如手册页所说:在某些非 UNIX 系统上,fpos_t 对象可能是复杂对象,这些例程可能是可移植地重新定位文本流的唯一方法。 @Mecki 是的,这个答案是错误的。据我了解,我下面的答案是唯一正确的。 否 答案不是不正确,而是不足。它正确地说明了fseek 和朋友的限制,并且正确地说明了fgetpos 和朋友是没有此类限制的选项。上面的答案从来没有说你可以混合fseekfsetpos和firends,这确实很危险。此外,它从未声明 fpos_t 是一个整数类型。相反,Mecki 建议 fseeko 和 firends 是非 ISO-C 标准函数(但 POSIX 函数)。【参考方案3】:

fgetpos() 与 fsetpos() 一起使用。 ftell() 与 fseek() 一起使用。

fgetpos() 看起来几乎像 ftell() 因为两者都采用 FILE* 参数,并且都返回文件中的某种位置,尽管风格略有不同。但是得到这个:只有 fseek() 允许您从文件的开头、文件中的当前位置和文件的末尾向后搜索(fseek() 的第三个参数是 SEEK_SET、SEEK_CUR 和 SEEK_END )。 fsetpos() 不这样做。 fsetpos() 仅限于返回从 fgetpos() 获得的某个位置。

假设您要将文件读入内存。 malloc() 需要多少堆?您需要文件的大小。而且我还没有在 C 标准库中找到任何可以告诉您文件大小的函数,尽管一些 C 编译器可能会添加非标准函数。例如,Borland Turbo C 有 filelength()。但我没有在标准 C 库中看到 filelength()。

所以,你可以做的是在文件 END 之前使用 fseek() 到 0 字节。然后使用 ftell() 以字节为单位获取位置,并以此为基础计算堆内存量。

您还能做些什么来获取文件大小?您可以使用 fgetc() 来读取每个字符,一直数到最后。但我认为使用 fseek() 和 ftell() 更好更容易。

【讨论】:

【参考方案4】:

虽然接口定义不同,但功能上没有区别。它们都被实现了,因为它们都是 POSIX 的一部分。

【讨论】:

这两个接口都来自 ISO C,而不是 POSIX。当文件变得非常大时,会出现巨大的功能差异。 他们的不同之处在于解决职位的方式:long intfpos_t

以上是关于fgetpos/fsetpos 和 ftell/fseek 有啥区别的主要内容,如果未能解决你的问题,请参考以下文章

用c语言如何读取和保存jpg图片文件?

& 和 && 区别和联系,| 和 || 区别和联系

第三十一节:扫盲并发和并行同步和异步进程和线程阻塞和非阻塞响应和吞吐等

shell中$()和 ` `${}${!}${#}$[] 和$(()),[ ] 和(( ))和 [[ ]]

Java基础8---面向对象代码块和继承和this和super和重写和重载和final

Java基础8---面向对象代码块和继承和this和super和重写和重载和final