Чтение больших двоичных файлов (> 2 ГБ) с python - PullRequest
0 голосов
/ 16 января 2020

Я пишу программу для обработки некоторых двоичных файлов. Раньше я использовал numpy.fromfile, и все работало нормально, пока не наткнулся на какой-то большой двоичный файл (> 2 ГБ), поскольку numpy не может прочитать их (проблемы с памятью) после неудачной попытки с h5py, так как я не понял, как конвертировать мои файлы в файлы h5. Я пытался использовать open(), read() и struct.unpack_from, чтобы восстановить данные, как я сделал бы в c ++.

Мои двоичные файлы представляют 32-разрядные числа с плавающей точкой, которые должны быть соединены в 64-битный комплекс.

Проблема на данный момент в том, что даже если из информации, которую я собрал, struct.unpack_from() должен вернуть кортеж со всеми данными указанного типа в файле, он возвращает только первый элемент файла :

Код:

f1 = open(IQ_File, 'rb')
a1 = f1.read()       
f = struct.unpack_from('f', a1)
print(f)

Я ожидаю, что здесь вывод с бинарным задним числом с плавающей запятой, однако мой вывод только:

(-0.057812511920928955,)

- - кортеж, содержащий только первое плавание файла.

Я действительно не понимаю, что я делаю здесь неправильно. Что я должен делать по-другому?

Ответы [ 2 ]

1 голос
/ 16 января 2020

Строки формата упаковки / распаковки могут иметь каждый элемент с префиксом числа, чтобы иметь столько упакованных / распакованных элементов. Просто разделите размер данных на размер float и поместите это число в формате:

nf = len(a1) // struct.calcsize('f')
f = struct.unpack(f"{nf}f", a1)

Помните, что кортежи являются очень неэффективным способом хранения данных массива чисел c в Python. В 64-битных системах (например, macOS) с CPython кортеж с N числами с плавающей запятой использует 24+N*8 байтов (sizeof(PyObject_VAR_HEAD) + N указателей) для самого кортежа плюс N*24 байтов ( sizeof(PyObject_HEAD) + один double) для чисел с плавающей запятой (хранится внутренне как double) или всего 24+N*32 байт. Это в 8 раз больше, чем размер двоичных данных!

Лучшим вариантом является использование numpy.fromfile() и явное предоставление аргументов count и, возможно, offset для чтения файла в виде фрагментов. Если вам нужно заранее узнать, сколько всего чисел есть в файле, используйте os.stat():

nf = os.stat(IQ_File).st_size // struct.calcsize('f')
1 голос
/ 16 января 2020

unpack_from('f', data) читает одно число с плавающей точкой из data. Вы, вероятно, ищете

for f in iter_unpack('f', a1):
    print(a1)

Вы, вероятно, можете сделать это более эффективным, прочитав только небольшой объем файла (скажем, 64 КБ за раз) в отдельном l oop.

...