【问题标题】:Unable to read huge (20GB) file from CPython无法从 CPython 读取巨大 (20GB) 文件
【发布时间】:2013-11-07 19:08:00
【问题描述】:

我有一些我无法理解的 CPython 问题。这一切都归结为这样一个事实,即使用相同的代码读取小文本文件有效,但甚至无法从 20GB txt 文件中读取一行。

一些有用的信息:

  • ~1MB 的小文件是 20GB 大文件的子集(从一开始就是 1MB)
  • 这两个文件都是文本文件,行宽 ~2000chars,由 CR (\r) 分隔

显而易见的解决方案:

f = open(r'filename', 'r')
for line in f:
    print(line)
f.close()

有效...但是..仅适用于短文件。因为大的永远挂起(或者至少打印第一行应该花费更长的时间)。

所以我想至少试着读这样一行:

f = open(r'filename', 'r')
print(f.readline())
f.close()

类似的情况 - 立即适用于小文件,但在大量时间吐出该消息后适用于大文件:

Traceback (most recent call last):
  File "***", line 16, in <module>
    print(f.readline())
SystemError: ..\Objects\stringobject.c:3902: bad argument to internal function

我应该如何阅读大文本文件?

更新:

事实证明,如果有足够的睡眠,人类会更清楚地思考 ;-)。问题解决了——原来我忽略了文档中的一句话:

Python 通常在构建时支持通用换行符; 提供 'U' 以文本文件形式打开文件,但行可能会被以下任何一种终止:Unix 行尾约定 '\n',Macintosh 约定 '\r' , 或 Windows 约定 '\r\n'。

只是认为通用换行符默认是“开启”的。

我上面的声明是:

print(f.readline())

只读了一行是部分错误(我的错)。还记得我说过我的小文件是通过大文件的一部分创建的吗?在那次操作中,行尾从(CR)变为(CRLF),所以我看到的是第一行。所有这一切让我觉得问题不在行尾。

感谢大家的时间和帮助。

【问题讨论】:

  • 当您对较小的文件使用 f.readline() 策略(不在循环中的策略)时,它是只打印一行,还是打印整个文件?我问是因为如果它打印整个文件,这表明文件中的 CR 没有被计为 Python 的 readline() 中的换行符。在这种情况下,您需要一个 read(chunk_size) 策略。
  • @Andrew:只是第一行,所以它(恕我直言)与无法检测到这个结尾无关 - 此外 Python 的文档说 \r、\r\n、\n 被视为相同作为行分隔符。
  • 如果它行尾问题,请尝试使用模式'rU'打开文件以获取通用行尾。
  • 如果你这样做f.read(1024)会发生什么?

标签: python file io


【解决方案1】:

虽然您的“测试”只打印一行,但这并不意味着它只从文件中读取一行。对我来说,在\r-delimited 测试文件中,我也只能得到一行输出。但是,如果我使用for 循环读取每一行,它仍然 只打印一行。或者,如果我在多行文件上再次尝试 readline(),它不会再提供任何行。

尝试在同一文件上使用'rU' 参数打开您的文件:

f =  open('filename', 'rU')

我对包含几行\r-delimited 文本的文件的测试给出:

f = open('test.txt','r')  # Opening the "wrong" way
for line in f:
    print line

输出:

abcdef

然后rU:

f = open('test.txt','rU')
for line in f:
    print line

输出:

abcdef

abcdef

abcdef

abcdef

abcdef

编辑:为了支持 Joran 的解释,这个测试几乎表明,当您只看到一行时,整个文件正在加载并且回车符导致过度打印输出...

f = open('test.txt','r')     #  Opening the "wrong" way again
for line in f:
    print "XXX{}YYY".format(line)

输出被覆盖...

YYYdefdef

【讨论】:

  • 这是一个非常好的观点...... python 中的 afaik \r 将您移回行首,可能会覆盖前一行...所以只是因为您看到一行不一定意味着只有一个
  • 这很好地解释了为什么输出看起来如此。谢谢乔兰。
  • 例如print "hello\rworld"
  • 完全正确,甚至更好,print "hello\ryou"
【解决方案2】:
def my_readline(fh,delim):
    return "".join(iter(lambda:fh.read(1),delim))

f = open(some_file)
line = my_readline(f,"\r")

如果你至少可以让.read(1) 工作应该可以工作......但如果这不起作用我不知道会有什么......也许使用shell命令以某种方式将文件拆分成更小的块......但我怀疑beroe的答案是真正的答案

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-04
    • 1970-01-01
    • 2021-05-29
    相关资源
    最近更新 更多