我有一个大文本文件,我需要使用python解析为管道分隔的文本文件。该文件看起来像这样(基本上):
product/productId: D7SDF9S9
review/userId: asdf9uas0d8u9f
review/score: 5.0
review/some text here
product/productId: D39F99
review/userId: fasd9fasd9f9f
review/score: 4.1
review/some text here
每条记录由两个换行章程/n
分隔。我在下面写了一个解析器。
with open ("largefile.txt", "r") as myfile:
fullstr = myfile.read()
allsplits = re.split("\n\n",fullstr)
articles = []
for i,s in enumerate(allsplits[0:]):
splits = re.split("\n.*?: ",s)
productId = splits[0]
userId = splits[1]
profileName = splits[2]
helpfulness = splits[3]
rating = splits[4]
time = splits[5]
summary = splits[6]
text = splits[7]
fw = open(outnamename,'w')
fw.write(productId+"|"+userID+"|"+profileName+"|"+helpfulness+"|"+rating+"|"+time+"|"+summary+"|"+text+"\n")
return
问题是我正在读取的文件太大,以至于在完成之前我的内存耗尽。我怀疑它正在allsplits = re.split("\n\n",fullstr)
线上徘徊。
有人可以告诉我一种方法,一次只读一个记录,解析它,写入文件,然后移动到下一条记录?
答案 0 :(得分:6)
不要一次性将整个文件读入内存;通过使用这些换行符生成记录。使用csv
module写入数据,以便于写出管道分隔的记录。
以下代码一次读取输入文件行,并在您继续写入每个记录的CSV行。它永远不会在内存中保留多行,加上一条正在构建的记录。
import csv
import re
fields = ('productId', 'userId', 'profileName', 'helpfulness', 'rating', 'time', 'summary', 'text')
with open("largefile.txt", "r") as myfile, open(outnamename,'w', newline='') as fw:
writer = csv.DictWriter(fw, fields, delimiter='|')
record = {}
for line in myfile:
if not line.strip() and record:
# empty line is the end of a record
writer.writerow(record)
record = {}
continue
field, value = line.split(': ', 1)
record[field.partition('/')[-1].strip()] = value.strip()
if record:
# handle last record
writer.writerow(record)
此代码确实假定文件包含category/key
形式的冒号之前的文本,因此product/productId
,review/userId
等等。斜杠后面的部分用于CSV列;顶部的fields
列表反映了这些键。
或者,您可以删除该fields
列表并使用csv.writer
代替,然后在列表中收集记录值:
import csv
import re
with open("largefile.txt", "r") as myfile, open(outnamename,'wb') as fw:
writer = csv.writer(fw, delimiter='|')
record = []
for line in myfile:
if not line.strip() and record:
# empty line is the end of a record
writer.writerow(record)
record = []
continue
field, value = line.split(': ', 1)
record.append(value.strip())
if record:
# handle last record
writer.writerow(record)
此版本要求记录字段全部存在并以固定顺序写入文件。
答案 1 :(得分:0)
使用“readline()”逐个读取记录的字段。或者您可以使用read(n)读取“n”个字节。
答案 2 :(得分:0)
不要一次将整个文件读入内存,而是逐行迭代,也使用Python的csv
module来解析记录:
import csv
with open('hugeinputfile.txt', 'rb') as infile, open('outputfile.txt', 'wb') as outfile:
writer = csv.writer(outfile, delimiter='|')
for record in csv.reader(infile, delimiter='\n', lineterminator='\n\n'):
values = [item.split(':')[-1].strip() for item in record[:-1]] + [record[-1]]
writer.writerow(values)
这里有几点需要注意:
with
打开文件。为什么?因为使用with
确保文件为close()
d,即使异常中断了脚本。因此:
with open('myfile.txt') as f:
do_stuff_to_file(f)
相当于:
f = open('myfile.txt')
try:
do_stuff_to_file(f)
finally:
f.close()
继续......(我没时间ATM)