【问题标题】:fseek to a 32-bit unsigned offsetfseek 到 32 位无符号偏移量
【发布时间】:2017-12-10 14:06:14
【问题描述】:

我正在读取一种文件格式 (TIFF),它从文件的开头开始有 32 位无符号偏移量。

不幸的是 fseek 的原型,我通常会去特定的文件偏移量,是:

int fseek ( FILE * stream, long int offset, int origin );

所以偏移量是有符号的。我应该如何处理这种情况?我应该使用不同的功能进行搜索吗?

【问题讨论】:

  • 您使用的是什么操作系统?您使用的是 32 位架构吗?
  • @melpomene 代码需要同时在 32 位和 64 位架构上运行,并且可以在不同的机器和操作系统上运行。
  • 大于 2 或 4 吉字节的 TIFF 文件并不罕见。您的 CRT 有一个需要很长的参数的替代方案,您必须查看它的文档。

标签: c file types io tiff


【解决方案1】:

在更深入地研究了这个问题并考虑了其他 cmets 和答案(谢谢)之后,我认为最简单的方法是如果偏移量大于 2147483647 字节,则进行两次搜索。这使我可以将偏移量保持为uint32_t 并继续使用fseek。因此定位代码是这样的:

// note: error handling code omitted
uint32_t offset = ... (whatever it is)
if( offset > 2147483647 ){
   fseek( file, 2147483647, SEEK_SET );
   fseek( file, (long int)( offset - 2147483647 ), SEEK_CUR );
} else {
   fseek( file, (long int) offset, SEEK_SET );
}

使用 64 位类型的问题在于代码可能在 32 位架构上运行(除其他外)。有一个函数 fsetpos 使用结构 fpos_t 来管理任意大的偏移量,但这带来了一系列复杂性。虽然fsetpos 可能在我真正使用任意大尺寸的偏移量时有意义,但因为我知道最大可能的偏移量是 uint32_t,所以双查找满足了这一需求。

请注意,此解决方案允许在 32 位系统上处理所有 TIFF 文件。如果您考虑像 PixInsight 这样的商业程序,这样做的好处是显而易见的。 PixInsight 在 32 位系统上运行时只能处理小于 2147483648 字节的 TIFF 文件。要处理完整大小的 TIFF 文件,用户必须在 64 位计算机上使用 64 位版本的 PixInsight。这可能是因为 PixInsight 程序员使用 64 位类型在内部处理偏移量。由于我的解决方案仅使用 32 位类型,因此我可以在 32 位系统上处理全尺寸 TIFF 文件(只要底层操作系统可以处理那么大的文件)。

【讨论】:

    【解决方案2】:

    您可以尝试使用lseek64() (man page)

      #define _LARGEFILE64_SOURCE     /* See feature_test_macros(7) */
      #include <sys/types.h>
      #include <unistd.h>
    
      off64_t lseek64(int fd, off64_t offset, int whence);
    

      int fd = fileno (stream);
    

    来自The GNU C lib - Setting the File Position of a Descriptor的笔记

    此函数类似于 lseek 函数。不同之处在于 offset 参数的类型是 off64_t 而不是 off_t,这使得在 32 位机器上可以寻址大于 2^31 字节和最多 2^63 字节的文件。文件描述符文件必须使用 open64 打开,否则 off64_t 可能的大偏移量将导致小文件模式下的描述符错误。

    当在 32 位机器上使用 _FILE_OFFSET_BITS == 64 编译源文件时,此函数实际上可以在名称 lseek 下使用,因此透明地替换了 32 位接口。

    关于fdstream,来自Streams and File Descriptors

    由于流是根据文件描述符实现的,因此您可以从流中提取文件描述符并直接对文件描述符执行低级操作。您还可以最初将连接作为文件描述符打开,然后创建与该文件描述符关联的流。

    【讨论】:

    • fseeko 不是更适合替代fseek 吗? lseek64 不适用于 FILE *
    • lseek64 使用fd,但在答案顶部附近,有一种方法可以从FILE *int fd = fileno(stream); (fileno) 中检索fd /跨度>
    • FILE 的底层文件描述符混淆听起来像是混淆 stdio 和破坏数据的好方法。
    • 我不需要处理大于 2^31 字节的文件。它可以是 32 位,但必须是 UNSIGNED 32 位。
    • @TylerDurden 那我不明白这个问题。 fseek 怎么了?
    猜你喜欢
    • 2015-10-21
    • 1970-01-01
    • 2011-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-17
    • 2019-10-31
    • 2015-09-18
    相关资源
    最近更新 更多