Чтение определенных разделов двоичного файла, содержащего 32-разрядные числа с плавающей запятой - PullRequest
0 голосов
/ 21 ноября 2018

У меня есть двоичный файл, который содержит 32-разрядные числа с плавающей точкой.Мне нужно иметь возможность читать определенные разделы файла в list или другую массивоподобную структуру.Другими словами, мне нужно считывать определенное количество байтов (определенное количество float32 s) за раз в мою структуру данных, а затем использовать 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 голосов
/ 21 ноября 2018

Вы можете преобразовать байты в и из 32-битных float значений, используя модуль struct:

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-битные, а затем обратно.

0 голосов
/ 21 ноября 2018

Двоичная информация из вашего входного файла может быть легко сопоставлена ​​с виртуальной памятью с помощью 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...