首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用python解析大(9 9GB)文件

使用python解析大(9 9GB)文件
EN

Stack Overflow用户
提问于 2014-02-09 08:46:31
回答 3查看 13K关注 0票数 4

我有一个很大的文本文件,我需要使用python将其解析成一个以竖线分隔的文本文件。文件看起来(基本上)是这样的:

代码语言:javascript
运行
复制
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分隔。我已经在下面写了一个解析器。

代码语言:javascript
运行
复制
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)生产线上的重击。

有没有人可以告诉我一种方法,一次只读入一条记录,解析它,将它写到文件中,然后移动到下一条记录?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-02-09 09:00:39

不要一次性将整个文件读入内存;要利用这些换行符来生成记录。使用csv module写入数据,以便写出以竖线分隔的记录。

下面的代码一次读取输入文件行,并在执行过程中写出每个记录的CSV行。它永远不会在内存中保存超过一行,外加正在构造的一条记录。

代码语言:javascript
运行
复制
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/productIdreview/userId等。斜杠后的部分用于CSV列;顶部的fields列表反映这些键。

或者,您可以删除该fields列表,转而使用csv.writer,在列表中收集记录值:

代码语言:javascript
运行
复制
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)

此版本要求所有记录字段都存在,并以固定顺序写入文件。

票数 6
EN

Stack Overflow用户

发布于 2014-02-09 08:53:08

使用"readline()“逐个读取记录的字段。或者您可以使用read(n)来读取"n“个字节。

票数 0
EN

Stack Overflow用户

发布于 2014-02-09 08:57:26

不要一次将整个文件读入内存,而是逐行迭代,还要使用Python的csv module来解析记录:

代码语言:javascript
运行
复制
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)

这里有几件事需要注意:

  • Use with 打开文件。为什么?因为使用with可以确保文件是close()d,即使异常中断脚本也是如此。

因此:

代码语言:javascript
运行
复制
with open('myfile.txt') as f:
    do_stuff_to_file(f)

等同于:

代码语言:javascript
运行
复制
f = open('myfile.txt')
try:
    do_stuff_to_file(f)
finally:
    f.close()

待续..。(我的自动取款机没时间了)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21653738

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档