【问题标题】:Memory Error Python Processing Large File Line by Line内存错误Python逐行处理大文件
【发布时间】:2017-07-15 02:30:51
【问题描述】:

我正在尝试连接模型输出文件,模型运行被分成 5 个,每个输出对应于其中一个部分运行,由于软件输出到文件的方式,它从每个文件的 0 开始重新标记输出。我写了一些代码:

1) 将所有输出文件连接在一起 2) 编辑合并的文件以重新标记所有时间步长,从 0 开始,每增加一个增量。

目的是我可以将这个单个文件一次性加载到我的可视化软件中,而不是打开 5 个不同的窗口。

到目前为止,由于我正在处理的文件很大,我的代码会引发内存错误。

我对如何尝试摆脱它有一些想法,但我不确定什么会起作用或/并且可能会减慢速度。

到目前为止的代码:

import os
import time

start_time = time.time()

#create new txt file in smae folder as python script

open("domain.txt","w").close()


"""create concatenated document of all tecplot output files"""
#look into file number 1

for folder in range(1,6,1): 
    folder = str(folder)
    for name in os.listdir(folder):
        if "domain" in name:
            with open(folder+'/'+name) as file_content_list:
                start = ""
                for line in file_content_list:
                    start = start + line# + '\n' 
                with open('domain.txt','a') as f:
                    f.write(start)
              #  print start

#identify file with "domain" in name
#extract contents
#append to the end of the new document with "domain" in folder level above
#once completed, add 1 to the file number previously searched and do again
#keep going until no more files with a higher number exist

""" replace the old timesteps with new timesteps """
#open folder named domain.txt
#Look for lines:
##ZONE T="0.000000000000e+00s", N=87715, E=173528, F=FEPOINT, ET=QUADRILATERAL
##STRANDID=1, SOLUTIONTIME=0.000000000000e+00
# if they are found edits them, otherwise copy the line without alteration

with open("domain.txt", "r") as combined_output:
    start = ""
    start_timestep = 0
    time_increment = 3.154e10
    for line in combined_output:
        if "ZONE" in line:
            start = start + 'ZONE T="' + str(start_timestep) + 's", N=87715, E=173528, F=FEPOINT, ET=QUADRILATERAL' + '\n'
        elif "STRANDID" in line:
            start = start + 'STRANDID=1, SOLUTIONTIME=' + str(start_timestep) + '\n'
            start_timestep = start_timestep + time_increment
        else:
            start = start + line

    with open('domain_final.txt','w') as f:
        f.write(start)

end_time = time.time()
print 'runtime : ', end_time-start_time

os.remove("domain.txt")

到目前为止,我在连接阶段遇到了内存错误。

为了改进我可以:

1) 尝试在阅读每个文件时随时进行更正,但由于它已经无法通过整个文件,我认为除了计算时间之外不会有太大的不同

2) 将所有文件加载到一个数组中,并创建一个检查函数并在数组上运行该函数:

类似:

def do_correction(line):
        if "ZONE" in line:
            return 'ZONE T="' + str(start_timestep) + 's", N=87715, E=173528, F=FEPOINT, ET=QUADRILATERAL' + '\n'
        elif "STRANDID" in line:
            return 'STRANDID=1, SOLUTIONTIME=' + str(start_timestep) + '\n'
        else:
            return line

3) 保持原样并要求 Python 指示它何时将耗尽内存并在该阶段写入文件。有人知道这是否可能吗?

感谢您的帮助

【问题讨论】:

  • 我不明白您为什么不即时而不是在最后写入数据。这是符合流的(注意:由于字符串连接,它必须花费很长时间)。你必须完全重写你的代码。
  • 在 for 循环之前打开输出并将每一行的结果直接写入输出文件。否则你的“开始”变量会被非常大的文件炸毁。
  • 我认为写入文件是一项代价高昂的操作,因此我想将所有内容堆叠在一个字符串中,并在末尾使用单个 write() 语句写入该字符串。从您的评论中,我了解到在每一行都有一个 f.write() 会更快。
  • 输入和输出由 Python 缓冲,因此您无需过多关心。
  • 我还需要在每个for line in file_content_list 的末尾加上file_content_list.close() 还是没有区别?

标签: python memory io out-of-memory


【解决方案1】:

在写入输出文件之前,不必将每个文件的全部内容读入内存。大文件只会消耗(可能是所有)可用内存。

一次只需读取和写入一行。也只打开一次输出文件......并选择一个不会被拾取并视为输入文件本身的名称,否则您将冒着将输出文件连接到自身的风险(这还不是问题,但如果您还可以处理当前目录中的文件) - 如果加载它还没有消耗所有内存。

import os.path

with open('output.txt', 'w') as outfile:
    for folder in range(1,6,1): 
        for name in os.listdir(folder):
            if "domain" in name:
                with open(os.path.join(str(folder), name)) as file_content_list:
                    for line in file_content_list:
                        # perform corrections/modifications to line here
                        outfile.write(line)

现在您可以以面向行的方式处理数据 - 只需在写入输出文件之前对其进行修改。

【讨论】:

    猜你喜欢
    • 2017-07-12
    • 1970-01-01
    • 1970-01-01
    • 2017-07-28
    • 2021-10-29
    • 2018-01-18
    • 1970-01-01
    • 2020-08-10
    相关资源
    最近更新 更多