在python中使用低内存从大文件中获取单词

在python中使用低内存从大文件中获取单词,python,Python,我需要迭代文件中的单词。文件可能非常大(超过1TB),行可能非常长(可能只有一行)。单词是英语,所以大小合理。所以我不想加载整个文件甚至整行 我有一些代码可以工作,但如果行太长(在我的机器上超过3GB),代码可能会爆炸 您能告诉我如何简单地重写此迭代器函数,使其在内存中的容量不超过所需的容量吗?不要逐行读取,而是读取缓冲块: import re def words(file, buffersize=2048): buffer = '' for chunk in iter(lam

我需要迭代文件中的单词。文件可能非常大(超过1TB),行可能非常长(可能只有一行)。单词是英语,所以大小合理。所以我不想加载整个文件甚至整行

我有一些代码可以工作,但如果行太长(在我的机器上超过3GB),代码可能会爆炸


您能告诉我如何简单地重写此迭代器函数,使其在内存中的容量不超过所需的容量吗?

不要逐行读取,而是读取缓冲块:

import re

def words(file, buffersize=2048):
    buffer = ''
    for chunk in iter(lambda: file.read(buffersize), ''):
        words = re.split("\W+", buffer + chunk)
        buffer = words.pop()  # partial word at end of chunk or empty
        for word in (w.lower() for w in words if w):
            yield word

    if buffer:
        yield buffer.lower()            
我正在使用的可调用和sentinel版本处理从文件中读取的操作,直到
file.read()
返回一个空字符串;与
while
循环相比,我更喜欢这种形式

如果您使用的是Python 3.3或更新版本,则可以在此处使用:

演示使用一个小的块大小来演示这一点,所有的工作都如预期的那样:

>>> demo = StringIO('''\
... Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque in nulla nec mi laoreet tempus non id nisl. Aliquam dictum justo ut volutpat cursus. Proin dictum nunc eu dictum pulvinar. Vestibulum elementum urna sapien, non commodo felis faucibus id. Curabitur
... ''')
>>> for word in words(demo, 32):
...     print word
... 
lorem
ipsum
dolor
sit
amet
consectetur
adipiscing
elit
pellentesque
in
nulla
nec
mi
laoreet
tempus
non
id
nisl
aliquam
dictum
justo
ut
volutpat
cursus
proin
dictum
nunc
eu
dictum
pulvinar
vestibulum
elementum
urna
sapien
non
commodo
felis
faucibus
id
curabitur

查看python如何逐字符读取文件如果单词是整行,您可能仍然有问题,但在这种情况下,您可以提前删除它。相关:在代码审阅后,我运行了它,但将块大小更改为
3
。没有发现问题。我唯一不喜欢的是它不是超优雅的。其他人可以制作更简单的东西吗?@richard:在Python 3.3及更高版本中,您可以使用
yield from map(str.lower,filter(None,words))
代替
for words:
循环,并且您可以使用
while chunk:
循环和两个
chunk=file.read(buffersize)
调用(一个用于初始化
循环,一个在循环中)而不是
iter()
——我使用了可调用和哨兵结构,但是除非您使用
mmap
解决方案,否则这几乎就是它。注意:mmap答案不会起作用,因为它试图将一个潜在的大文件(>1TB)映射到一个潜在的小进程(~3Gb)中。(答案现已删除)
def words(file, buffersize=2048):
    buffer = ''
    for chunk in iter(lambda: file.read(buffersize), ''):
        words = re.split("\W+", buffer + chunk)
        buffer = words.pop()  # partial word at end of chunk or empty
        yield from (w.lower() for w in words if w)

    if buffer:
        yield buffer.lower()            
>>> demo = StringIO('''\
... Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque in nulla nec mi laoreet tempus non id nisl. Aliquam dictum justo ut volutpat cursus. Proin dictum nunc eu dictum pulvinar. Vestibulum elementum urna sapien, non commodo felis faucibus id. Curabitur
... ''')
>>> for word in words(demo, 32):
...     print word
... 
lorem
ipsum
dolor
sit
amet
consectetur
adipiscing
elit
pellentesque
in
nulla
nec
mi
laoreet
tempus
non
id
nisl
aliquam
dictum
justo
ut
volutpat
cursus
proin
dictum
nunc
eu
dictum
pulvinar
vestibulum
elementum
urna
sapien
non
commodo
felis
faucibus
id
curabitur