C处理大文件

8

我需要解析一个可能有几个GB大小的文件。我想用C语言实现这个功能。有人能提供一些方法来完成这个任务吗?

我需要打开和解析的文件是我从我的Mac硬盘中获取的硬盘转储文件。然而,我计划在64位Ubuntu 10.04中运行我的程序。另外,考虑到文件大小较大,所以最优化的方法越好。


1
C语言中用于打开文件的函数可以让你一次读取文件的一小部分,而不需要一次性将整个文件放入内存中。 - zneak
我并不一定要在内存中打开整个文件,但是如何访问一个偏移量高于最大c整数的字节数据呢? - romejoe
@romejoe,快速的谷歌搜索(man fseek)显示偏移量是long类型而不是int类型,因此您应该能够访问2GB。fseek还接受第三个参数,可以是SEEK_CUR,它将请求的偏移添加到当前位置。http://www.s-gms.ms.edus.si/cgi-bin/man-cgi?fseek+3C。还有fseeko用于64位偏移量。 - atk
@atk:在许多机器上,long类型是64位的,而且你可以读取的文件大小远大于2GB。@romejoe:INT_MAX是否等于LONG_MAX?你的机器上有'long long'(C99)吗? - Jonathan Leffler
@Jonthan Leffler,说得对。我更多地是回应了reomejoe关于如何绕过最大整数的问题,这意味着他在32位系统上。 - atk
5个回答

6
在*nix和Windows上,有扩展的I/O例程,可以触及文件大小,支持大于2GB或4GB的大小。自然地,底层文件系统也必须支持这么大的文件。在Windows上,NTFS支持这样的文件,但是FAT就不支持。这通常被称为“大文件支持”。
这两个对于这些目的最关键的例程是fseek()ftell(),以便您可以对整个文件进行随机访问。否则,普通的fopen()fread()和相关函数可以对任何大小的文件进行顺序访问,只要底层操作系统和stdio实现支持大文件即可。

1
假设您正在使用 Linux / BSD / Mac / NotWindows 64 位系统(说实话,现在谁不是呢?),mmap 的性能非常出色。它基本上允许您将整个文件映射到进程的地址空间中,并让内核为您执行缓存/分页。
如果您必须使用 Windows,则 此处 有相同的概念,但由 Redmond 的友好人士制作。请注意,对于这两者任何一种,您都应在 64 位系统上运行,因为您可以将其映射到 32 位系统上的绝对最大文件大小约为 ~ 4GB。

3
“谁现在不是这样呢?”关于64位操作系统。我敢打赌现实世界中(而不是游戏世界)的计算机/工作站有95-99%是32位的。 - R.. GitHub STOP HELPING ICE
内存映射很好,但考虑到提问者的简单问题,我认为他会寻找最基本的接口,而性能也没有被提及。 - Matt Joiner
请注意,即使在64位系统上,文件可能也比可以映射的空间大得多,因为当前一代64位CPU实际上仅具有48位地址空间。 128TB左右可能现在看起来很大,但是有那么大阶级的磁盘阵列存在。 - bdonlan
@R:我怀疑他不打算在普通电脑上阅读大文件。这很可能是为了服务器而设计的。 - Clark Gaebel

1
除了RBerteig和Matt的回答之外:
如果您在项目中为所有文件正确且仔细地启用64位IO支持(方法取决于系统),则如果使用正确的类型,您不必担心整数溢出。我认为off_t应该是定位文件指针的正确选择。
如果其他方法都失败了,假设类型的宽度,则使用正确的C99类型。使用intlong几乎总是错误的,它们太依赖编译器/平台。使用int64_t(如果没有,则使用int_fast64_t)。

4
这个答案有些误导性。仅仅使用正确的类型还不够,你需要使用能够处理偏移量的函数。在大多数Unix系统上(特别是Linux),默认的编译环境中off_t被定义为long,因此在32位机器上它只有32位。通常情况下,你需要使用-D_FILE_OFFSET_BITS=64选项对整个程序进行构建,并使用fseekoftello函数来获取合理的行为 - 当然也要使用off_t类型来保存偏移量变量。顺便说一句,即使你从不执行任何寻址操作,在没有大文件支持的情况下,IO也会在超过2GB的文件上失败。 - R.. GitHub STOP HELPING ICE
@R:你有没有读我回答的前几个单词?显然,我所说的其余部分并不足够,但这已经在RBerteig的回答中给出了。也许我的措辞不够好,我不是英语的母语者,但你会怎么说类似的话呢? - Jens Gustedt
这是有误导性的,因为它没有提到如何启用64位IO。仅仅使用off_t而不定义正确的宏是行不通的。 - bdonlan
@bdonlan:正如你在对Matt的回答中所提到的,这没有通用规则。但我会尝试重新表述我的答案,以使其更加清晰明了。 - Jens Gustedt

1

为所有相关源文件定义宏-D_FILE_OFFSET_BITS=64#define _FILE_OFFSET_BITS 64(最好是整个项目)。这个常见的宏由几个常见的构建系统自动提供。然后在API需要时使用off_t(现在将是64位)。


仅适用于POSIX系统。 - bdonlan

0

根据乔姆斯基层次的不同,可能有几个免费和商业工具包可用于创建文件格式的解析器。我认为你认为自己面临的真正问题是如何“处理”数GB的数据。

你想同时将所有数据存储在内存中吗?
一种方法是将文件的部分写入磁盘上的临时文件中,在不使用时。简单的结构体fread / fwrite和一些聪明的引用计数的“按需”加载和写入可以实现这一点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接