15

我正在解析一个 20Gb 文件并将满足特定条件的行输出到另一个文件,但是偶尔 python 会一次读取 2 行并将它们连接起来。

inputFileHandle = open(inputFileName, 'r')

row = 0

for line in inputFileHandle:
    row =  row + 1
    if line_meets_condition:
        outputFileHandle.write(line)
    else:
        lstIgnoredRows.append(row)

我检查了源文件中的行尾,它们作为换行符签出(ascii char 10)。提取问题行并单独解析它们可以按预期工作。我在这里遇到了一些 python 限制吗?第一个异常在文件中的位置在 4GB 标记附近。

4

2 回答 2

23

快速谷歌搜索“python 读取大于 4gb 的文件”产生了许多结果。请参阅此处以获取此类示例 以及从第一个继承的另一个示例。

这是 Python 中的一个错误。

现在,错误的解释;重现并不容易,因为它取决于内部 FILE 缓冲区大小和传递给 fread() 的字符数。在 Microsoft CRT 源代码中的 open.c 中,有一个块以这种令人鼓舞的评论开头“这是困难的部分。我们在缓冲区末尾发现了一个 CR。我们必须先看看下一个字符是否是 LF。 " 奇怪的是,在 Perl 源代码中有这个函数的几乎完全相同的副本:http://perl5.git.perl.org/perl.git/blob/4342f4d6df6a7dfa22a470aa21e54a5622c009f3: /win32/win32.c#l3668 问题在于对 SetFilePointer() 的调用,用于在前瞻后后退一个位置;它将失败,因为它无法以 32 位 DWORD 返回当前位置。[修复很容易;你看到了吗?] 此时,函数认为下一个 read() 将返回 LF,但它不会,因为文件指针没有移回。

解决方法:

但请注意,Python 3.x 不受影响(原始文件始终以二进制模式打开,CRLF 翻译由 Python 完成);对于 2.7,您可以使用 io.open()。

于 2012-04-19T02:53:01.427 回答
7

4GB 标记可疑地接近可以存储在 32 位寄存器 (2**32) 中的最大值。

您发布的代码本身看起来不错,所以我怀疑您的 Python 构建中存在错误。

FWIW,如果使用enumerate,该片段会更干净一些:

inputFileHandle = open(inputFileName, 'r')

for row, line in enumerate(inputFileHandle):
    if line_meets_condition:
        outputFileHandle.write(line)
    else:
        lstIgnoredRows.append(row)
于 2012-04-19T02:45:17.273 回答