阅读一个大的big-endian二进制文件

时间:2016-11-03 09:19:21

标签: python file io

我有一个非常大的big-endian二进制文件。我知道这个文件中有多少个数字。我找到了一个解决方案,如何使用struct读取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 mb,则此代码的工作速度非常慢。 我当前的文件大小为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在float中转换每4个bites。是否有可能使程序运行得更快?

3 个答案:

答案 0 :(得分:4)

您可以使用numpy.fromfile来阅读该文件,并在>参数中指定该类型为big-endian指定dtype

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

还有array.fromfile方法,但遗憾的是我无法看到任何可以控制字节序的方法,因此根据您的使用情况,这可能会避免依赖第三方库或无用。

答案 1 :(得分: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文档:

  

格式字符可以在整数重复计数之前。对于   例如,格式字符串&#4; 4h&#39;与&#39; hhhh&#39;完全相同。

答案 2 :(得分:0)

def read_big_endian(filename):
    all_text = ""
    with open(filename, "rb") as template:
        try:
            template.read(2)  # first 2 bytes are FF FE
            while True:
                dchar = template.read(2)
                all_text += dchar[0]
        except:
            pass
    return all_text


def save_big_endian(filename, text):
    with open(filename, "wb") as fic:
        fic.write(chr(255) + chr(254))  # first 2 bytes are FF FE
        for letter in text:
            fic.write(letter + chr(0))

用于读取.rdp文件

相关问题