我有一个非常大的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。是否有可能使程序运行得更快?
答案 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文件