读取包含32位浮点数的二进制文件的特定部分

时间:2018-11-21 18:58:41

标签: python python-3.x file-io

我有一个包含32位浮点数的二进制文件。我需要能够将文件的某些部分读取为list或其他类似数组的结构。换句话说,我需要一次读取特定数量的字节(特定数量的float32)到我的数据结构中,然后使用seek()查找文件中的另一点并执行同样的事情。

使用伪代码:

new_list = []

with open('my_file.data', 'rb') as file_in:
    for idx, offset in enumerate(offset_values):
        # seek in the file by the offset
        # read n float32 values into new_list[idx][:]

最有效/最容易混淆的方法是什么?

2 个答案:

答案 0 :(得分:2)

您可以使用struct模块在​​32位float值之间来回转换字节:

import random
import struct

FLOAT_SIZE = 4
NUM_OFFSETS = 5
filename = 'my_file.data'

# Create some random offsets.
offset_values = [i*FLOAT_SIZE for i in range(NUM_OFFSETS)]
random.shuffle(offset_values)

# Create a test file
with open(filename, 'wb') as file:
    for offset in offset_values:
        file.seek(offset)
        value = random.random()
        print('writing value:', value, 'at offset', offset)
        file.write(struct.pack('f', value))

# Read sections of file back at offset locations.

new_list = []
with open(filename, 'rb') as file:
    for offset in offset_values:
        file.seek(offset)
        buf = file.read(FLOAT_SIZE)
        value = struct.unpack('f', buf)[0]
        print('read value:', value, 'at offset', offset)
        new_list.append(value)

print('new_list =', new_list)

示例输出:

writing value: 0.0687244786128608 at offset 8
writing value: 0.34336034914481284 at offset 16
writing value: 0.03658244351244533 at offset 4
writing value: 0.9733690320097427 at offset 12
writing value: 0.31991994765615206 at offset 0
read value: 0.06872447580099106 at offset 8
read value: 0.3433603346347809 at offset 16
read value: 0.03658244386315346 at offset 4
read value: 0.9733690023422241 at offset 12
read value: 0.3199199438095093 at offset 0
new_list = [0.06872447580099106, 0.3433603346347809, 0.03658244386315346,
            0.9733690023422241, 0.3199199438095093]

请注意,回读的值略有不同,因为Python内部使用64位float值,因此在将它们转换为32位然后返回的过程中损失了一些精度。

答案 1 :(得分:0)

输入文件中的二进制信息可以很容易地映射到虚拟内存using mmap.,如果需要,您可以从那里将缓冲区导入numpy数组。请注意-numpy dtype可能会有所变化,具体取决于您的32位浮点数是带符号的还是无符号的(本示例假定带符号的)。填充的数组将包含数字(而不是原始字节)。

import mmap
import numpy as np
import os

new_list = []

with open('my_file.data', 'rb') as file_in:
    size_bytes = os.fstat(file_in.fileno()).st_size
    m = mmap.mmap(file_in.fileno(), length=size_bytes, access=mmap.ACCESS_READ)
    arr = np.frombuffer(m, np.dtype('float32'), offset=0)
    for idx, offset in enumerate(offset_values):
        new_list.append(arr[offset//4])  #For unsigned 32bit floats, divide by 8

我用n = 10000个随机浮点数组测试了这一点,将其转换为字节:

import random
import struct

a = ''
for i in range(10000):
    a += struct.pack('<f', random.uniform(0, 1000))

然后,我将这个“ a”变量读入numpy数组,就像读取文件中的二进制信息一样。

>>> arr = np.frombuffer(a, np.dtype('float32'), offset=0)
>>> arr[500]
634.24408