[英]Python read huge file line by line with utf-8 encoding
我想读一些非常大的文件(确切地说:谷歌ngram 1字数据集)并计算一个字符出现的次数。 现在我写了这个脚本:
import fileinput
files = ['../../datasets/googlebooks-eng-all-1gram-20090715-%i.csv' % value for value in range(0,9)]
charcounts = {}
lastfile = ''
for line in fileinput.input(files):
line = line.strip()
data = line.split('\t')
for character in list(data[0]):
if (not character in charcounts):
charcounts[character] = 0
charcounts[character] += int(data[1])
if (fileinput.filename() is not lastfile):
print(fileinput.filename())
lastfile = fileinput.filename()
if(fileinput.filelineno() % 100000 == 0):
print(fileinput.filelineno())
print(charcounts)
哪个工作正常,直到达到约。 第一个文件的700.000行,然后我得到这个错误:
../../datasets/googlebooks-eng-all-1gram-20090715-0.csv
100000
200000
300000
400000
500000
600000
700000
Traceback (most recent call last):
File "charactercounter.py", line 5, in <module>
for line in fileinput.input(files):
File "C:\Python31\lib\fileinput.py", line 254, in __next__
line = self.readline()
File "C:\Python31\lib\fileinput.py", line 349, in readline
self._buffer = self._file.readlines(self._bufsize)
File "C:\Python31\lib\encodings\cp1252.py", line 23, in decode
return codecs.charmap_decode(input,self.errors,decoding_table)[0]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x8d in position 7771: cha
racter maps to <undefined>
为了解决这个问题,我在网上搜索了一下,并想出了这段代码:
import fileinput
files = ['../../datasets/googlebooks-eng-all-1gram-20090715-%i.csv' % value for value in range(0,9)]
charcounts = {}
lastfile = ''
for line in fileinput.input(files,False,'',0,'r',fileinput.hook_encoded('utf-8')):
line = line.strip()
data = line.split('\t')
for character in list(data[0]):
if (not character in charcounts):
charcounts[character] = 0
charcounts[character] += int(data[1])
if (fileinput.filename() is not lastfile):
print(fileinput.filename())
lastfile = fileinput.filename()
if(fileinput.filelineno() % 100000 == 0):
print(fileinput.filelineno())
print(charcounts)
但是我现在使用的钩子试图将整个990MB的文件一次性读入内存,这会让我的电脑崩溃。 有谁知道如何重写这段代码,以便它真正起作用?
ps:代码还没有一直运行,所以我甚至不知道它是否做了它必须做的事情,但为了实现这一点,我首先需要修复这个bug。
哦,我使用的是Python 3.2
我不知道为什么fileinput没有按预期工作。
我建议你改用open
函数。 返回值可以迭代并返回行,就像fileinput一样。
代码将是这样的:
for filename in files:
print(filename)
for filelineno, line in enumerate(open(filename, encoding="utf-8")):
line = line.strip()
data = line.split('\t')
# ...
一些文档链接: enumerate , open , io.TextIOWrapper (open返回TextIOWrapper的一个实例)。
问题是fileinput
不使用file.xreadlines()
读取的file.xreadlines()
,而是使用file.readline(bufsize)
,它一次读取bufsize字节(并将其转换为行列表)。 您为fileinput.input()
的bufsize
参数提供0
(这也是默认值)。 Bufsize 0表示整个文件是缓冲的。
解决方案:提供合理的bufsize。
这适用于我:你可以在钩子定义中使用“utf-8”。 我在50GB / 200M线文件上使用它没有问题。
fi = fileinput.FileInput(openhook=fileinput.hook_encoded("iso-8859-1"))
你能不能尝试读取整个文件,但是它的一部分是二进制文件,然后是decode(),然后是proccess,然后再次调用该函数来读取另一部分?
如果我拥有的是最新版本(我不记得我是如何阅读的),我不会,但......
$ file -i googlebooks-eng-1M-1gram-20090715-0.csv
googlebooks-eng-1M-1gram-20090715-0.csv: text/plain; charset=us-ascii
您是否尝试过fileinput.hook_encoded('ascii')
或fileinput.hook_encoded('latin_1')
? 不知道为什么这会产生影响,因为我认为这些只是具有相同映射的unicode子集,但值得一试。
编辑我认为这可能是fileinput中的一个错误,这些都不是。
如果您担心内存使用情况,为什么不使用readline()逐行阅读? 这将消除您遇到的内存问题。 目前,您在对fileObj执行任何操作之前正在读取完整文件,而readline()则不是保存数据,而是仅按行进行搜索。
def charCount1(_file, _char):
result = []
file = open(_file, encoding="utf-8")
data = file.read()
file.close()
for index, line in enumerate(data.split("\n")):
if _char in line:
result.append(index)
return result
def charCount2(_file, _char):
result = []
count = 0
file = open(_file, encoding="utf-8")
while 1:
line = file.readline()
if _char in line:
result.append(count)
count += 1
if not line: break
file.close()
return result
我没有机会真正查看您的代码,但上述示例应该让您了解如何对您的结构进行适当的更改。 charCount1()演示了一个方法,它在read()的单个调用中缓存整个文件。 我在+ 400MB文本文件上测试了你的方法,python.exe进程高达+ 900MB。 当你运行charCount2()时 ,python.exe进程不应超过几MB(假设你没有用其他代码扩大它的大小);)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.