2016-11-03 50 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'完全相同。