Чтение 32-разрядных подписанных ieee 754 с плавающей запятой из двоичного файла с помощью python?

#python #parsing #floating-point #binaryfiles #ieee-754

#python #синтаксический анализ #с плавающей запятой #двоичные файлы #ieee-754

Вопрос:

У меня есть двоичный файл, который представляет собой простой список подписанных 32-разрядных чисел с плавающей запятой ieee754. Они ничем не разделены и просто отображаются один за другим до EOF.

Как бы я прочитал из этого файла и правильно интерпретировал их как числа с плавающей запятой?

Я пытался использовать read(4) , но он автоматически преобразует их в строку с кодировкой ascii.

Я также пытался использовать bytearray , но это занимает только 1 байт за раз вместо 4 байт за раз, как мне нужно.

Ответ №1:

 struct.unpack('f', file.read(4))
  

Вы также можете распаковать несколько одновременно, что будет быстрее:

 struct.unpack('f'*n, file.read(4*n))
  

Комментарии:

1. 1 для ‘f’ * n; где задокументирован этот синтаксис? Должно быть, я пропустил это в моем учебном пособии по Python.

2. Умножение строк описано в руководстве и в справочном разделе библиотеки по объектам sequence.

3. Более общим способом распаковки нескольких было бы unpack('{0}f'.format(n), ...) , или, если вы знаете, сколько заранее, тогда просто unpack('10f', ...) , например. Лучше использовать встроенный метод повторения, чем полагаться на манипулирование строками.

4. @cdiggins: Я склоняюсь к тому, что требует наименьшего количества ввода и легче всего читается. Эти два фактора иногда конфликтуют, поэтому вам, возможно, придется заменить один другим, но в этом случае моя версия и короче, и понятнее. С точки зрения производительности я ожидаю, что две формы будут почти идентичны, поскольку основная часть времени тратится в подсистеме ввода-вывода. Если длина известна во время кодирования, то я согласен, что '10f' это лучше, точно по тем же причинам: это немного короче и легче для чтения, чем 'f'*10 .

5. @Marcelo, я согласен с принципом, но рассмотрите возможность распаковки 100 000 целых чисел. Для меня не имеет смысла создавать строку формата длиной 100 кб. Вместо ‘{0}f’.формат (1000000) имеет больше смысла.

Ответ №2:

Взгляните на struct.распакуйте. Может сработать что-то вроде следующего…

 f = struct.unpack('f', data_read)
  

Ответ №3:

 import struct
(num,) = struct.unpack('f', f.read(4))
  

Ответ №4:

Самый быстрый подход (с точки зрения производительности) Пока я обнаружил, что это numpy.fromfile

 import numpy as np

class FloatReader:
    def __init__(self, filename):
        self.f = open(filename, "rb")
    
    def read_floats(self, count : int):
        return np.fromfile(self.f, dtype=np.float32, count=count, sep='')
  

Этот подход намного быстрее, чем struct.unpack с точки зрения производительности!