2016-11-03 78 views
2

我有一個非常大的big-endian二進制文件。我知道這個文件中有多少個數字。我發現了一個解決方案是如何利用結構來讀大端文件和它的作品完美的,如果文件很小:閱讀一個大的big-endian二進制文件

data = [] 
    file = open('some_file.dat', 'rb') 

    for i in range(0, numcount) 
      data.append(struct.unpack('>f', file.read(4))[0]) 

但是這個代碼的工作非常緩慢,如果文件大小超過〜100萬桶。 我目前的文件大小爲1.5GB,包含399.513.600個浮點數。上面的代碼與這個文件約8分鐘。

我找到了另一種解決方案,即工作速度快:

datafile = open('some_file.dat', 'rb').read() 
    f_len = ">" + "f" * numcount #numcount = 399513600 

    numbers = struct.unpack(f_len, datafile) 

這段代碼在大約〜1.5分鐘運行,但是這對我來說太緩慢。早些時候,我在Fortran中編寫了相同的功能代碼,並且它在大約10秒內運行。

在Fortran中,我打開帶有標誌「big-endian」的文件,我可以簡單地讀取REAL數組中的文件,而不進行任何轉換,但是在python中,我必須將文件讀爲字符串,並使用struct轉換每4個浮點數。有可能使程序運行得更快嗎?

+0

我也有'struct'的一些不好的經驗;一次讀取大約1GB的文件(您的第二個示例)完全可以使我的筆記本電腦(8GB)的內存達到最大,這當然會使一切非常緩慢。在我的情況下,以大塊閱讀是解決方案。 – Bart

回答

3

您可以使用numpy.fromfile讀取該文件,並指定該類型是大端在dtype參數指定>

numpy.fromfile(filename, dtype='>f') 

有一個array.fromfile方法也一樣,可惜我看不到任何方式您可以在其中控制字節順序,因此根據您的使用情況,這可能會避免依賴第三方庫或無用。

0

以下辦法給我一個很好的加速:

import struct 
import random 
import time 


block_size = 4096 
start = time.time() 

with open('some_file.dat', 'rb') as f_input:  
    data = [] 

    while True: 
     block = f_input.read(block_size * 4) 
     data.extend(struct.unpack('>{}f'.format(len(block)/4), block)) 

     if len(block) < block_size * 4: 
      break 

print "Time taken: {:.2f}".format(time.time() - start) 
print "Length", len(data) 

而不是使用>fffffff可以例如指定計數>1000f。它一次讀取文件4096大塊。如果讀取的數量少於此值,則調整塊大小並退出。

struct - Format Characters文檔:

格式字符可以通過一個整體的重複計數之前。例如,對於 示例,格式字符串'4h'的含義與'hhhh'完全相同。