簡體   English   中英

Python使用utf-8編碼逐行讀取大文件

[英]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')
        # ...

一些文檔鏈接: enumerateopenio.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM