【问题标题】:Seeking and reading large files in a Linux C++ application在 Linux C++ 应用程序中查找和读取大文件
【发布时间】:2024-01-03 12:16:01
【问题描述】:

我在使用 G++ 中的标准 ftellfseek 选项时遇到整数溢出,但我想我弄错了,因为似乎 ftell64 em> 和 fseek64 不可用。我一直在搜索,许多网站似乎使用 off64_t 数据类型的 lseek 进行引用,但我没有找到任何引用与 fseek 相同的示例.现在我正在阅读的文件是 16GB+ CSV 文件,预计至少会翻一番。

在没有任何外部库的情况下,实现与 fseek/ftell 对相似的结构的最直接方法是什么?我的应用程序现在使用 4.x 的标准 GCC/G++ 库工作。

【问题讨论】:

    标签: c++ c linux gnu large-files


    【解决方案1】:

    如果您想坚持使用 ISO C 标准接口,请使用 fgetpos()fsetpos()。但是,这些函数仅对保存文件位置和稍后返回相同位置有用。它们使用类型fpos_t 表示位置,不需要是整数数据类型。例如,在基于记录的系统上,它可以是一个包含记录编号和记录内偏移量的结构。这可能太局限了。

    POSIX 定义了函数ftello()fseeko(),它们使用off_t 类型表示位置。这需要是整数类型,并且值是从文件开头的字节偏移量。您可以对其执行算术运算,并可以使用fseeko() 执行相对查找。这将适用于 Linux 和其他 POSIX 系统。

    此外,使用-D_FILE_OFFSET_BITS=64 (Linux/Solaris) 进行编译。这会将off_t 定义为64 位类型(即off64_t)而不是long,并将使用文件偏移量的函数重新定义为采用64 位偏移量的版本。这是编译 64 位时的默认设置,因此在这种情况下不需要。

    【讨论】:

      【解决方案2】:

      您是否尝试过将 _FILE_OFFSET_BITS 预处理器符号设置为 64fseeko()

      这将为您提供一个类似 fseek() 的界面,但使用类型为 off_t 而不是 long 的偏移参数。设置 _FILE_OFFSET_BITS=64 将使 off_t 成为 64 位类型。

      ftello()也是如此。

      【讨论】:

        【解决方案3】:

        使用fsetpos(3)fgetpos(3)。他们使用 fpos_t 数据类型,我相信它可以保证至少能够保存 64 位。

        【讨论】:

          【解决方案4】:

          fseek64 是一个 C 函数。要使其可用,您必须在包含系统标头之前定义 _FILE_OFFSET_BITS=64 这或多或少将 fseek 定义为实际上是 fseek64。或者在编译器参数中执行它,例如 gcc -D_FILE_OFFSET_BITS=64 ....

          http://www.suse.de/~aj/linux_lfs.html 对 linux 上的大文件支持有一个很好的概述:

          • 使用“gcc -D_FILE_OFFSET_BITS=64”编译您的程序。这会强制所有文件访问调用使用 64 位变体。几种类型也发生了变化,例如off_t 变为 off64_t。因此,重要的是始终使用正确的类型并且不使用例如int 而不是 off_t。为了与其他平台的可移植性,您应该使用 getconf LFS_CFLAGS 它将在 Linux 平台上返回 -D_FILE_OFFSET_BITS=64 但可能会在例如返回其他内容。索拉里斯。对于链接,您应该使用通过 getconf LFS_LDFLAGS 报告的链接标志。在 Linux 系统上,您不需要特殊的链接标志。
          • 定义 _LARGEFILE_SOURCE 和 _LARGEFILE64_SOURCE。通过这些定义,您可以直接使用 open64 等 LFS 函数。
          • 使用 O_LARGEFILE 标志和 open 来操作大文件。

          【讨论】:

          • 所以,我按照你的指示,一切都在编译文件。但我似乎仍在溢出。您将如何在 fopen64 中使用 O_LARGEFILE 参数?
          • 如果您使用 -D_FILE_OFFSET_BITS=64 进行编译,则会自动提供 O_LARGEFILE。这不是标准标志;它在 Linux 上用于跟踪文件是否使用大文件接口打开。
          • 您以 C++ 的身份提出了这个问题,您是在使用/混合 C 文件操作与 C++ 流,还是仅使用 C API?另外,您是否有一些测试代码来重现该行为?使用正确的类型处理长度/偏移量至关重要。
          • 我只使用 C API,并且一直使用 off64_t 作为我的类型。
          • 这个答案的关键是 -D_FILE_OFFSET_BITS=64 并且实际上是解决我的问题的原因。当使用多个共享库时,我的建议是将其应用于所有构建 Makefile。
          【解决方案5】:

          fseek64() 不是标准的,编译器文档应该会告诉您在哪里可以找到它。

          你试过fgetposfsetpos吗?它们是为大文件设计的,实现通常使用 64 位类型作为 fpos_t 的基础。

          【讨论】: