2017-02-24 69 views
0

我想連接模型輸出文件,模型運行分解爲5,每個輸出對應於其中一個部分運行,由於軟件輸出到文件的方式在每個文件輸出上從0開始重新標記。我寫了一些代碼:內存錯誤Python處理大型文件行按行

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指出它何時即將耗盡內存並在該階段寫入文件。任何人都知道這是可能的嗎?

謝謝您的幫助

+1

我不明白你爲什麼不直接寫數據而不是最後。這是符合流的(注意:由於字符串連接,它必須花費時間)。你必須完全重寫你的代碼。 –

+1

在for循環之前打開輸出,並將每行的結果直接寫入輸出文件。否則你的「開始」變量將會被非常大的文件炸燬。 – MKesper

+0

我認爲寫入文件是一個代價高昂的操作,所以我希望將所有內容都堆疊在一個字符串中,並且只需在單個write()語句的末尾寫入該字符串即可。從你的評論我收集到,每行有一個f.write()會更快。 – Sorade

回答

2

這是沒有必要寫入到輸出文件之前讀取每個文件的全部內容複製到內存中。大文件只會消耗所有可用的內存。

一次只能讀寫一行。另外打開一次輸出文件...並選擇一個不會被拾取的名稱,並將其視爲一個輸入文件本身,否則會冒着將輸出文件連接到自身的風險(這還不是問題,但可能是if你也處理來自當前目錄的文件) - 如果加載它並沒有消耗所有的內存。

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) 

現在您可以以面向行的方式處理數據 - 只需在寫入輸出文件之前對其進行修改即可。