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

Мне нужно обрабатывать десятки гигабайт данных в одном двоичном файле. Каждая запись в файле данных имеет переменную длину.

Итак, файл такой:

<len1><data1><len2><data2>..........<lenN><dataN>

Данные содержат целое число, указатель, двойное значение и так далее.

Я обнаружил, что Python не может даже справиться с этой ситуацией. Нет проблем, если я прочитаю весь файл в памяти. Это быстро. Но похоже, что пакет struct не очень хорош в производительности. Он почти застрял при распаковке байтов.

Любая помощь приветствуется.

Спасибо.


person limi    schedule 17.08.2009    source источник
comment
Пожалуйста, подскажите, что вы делали со структурой, которая была настолько плохой.   -  person S.Lott    schedule 17.08.2009
comment
Вы действительно уверены, что читаете данные в десятки гигабайт в памяти?   -  person rob    schedule 17.08.2009
comment
Действительно ли проблема с производительностью struct, или просто это занимает много времени? Даже с самым эффективным кодом возможная обработка десятков гигабайт данных займет некоторое время...   -  person Scott Griffiths    schedule 17.08.2009


Ответы (6)


struct и array, которые рекомендуют другие ответы, подходят для деталей реализации и могут быть всем, что вам нужно, если вам нужно всегда последовательно читать весь файл или его префикс. Другие параметры включают буфер, mmap, даже ctypes, в зависимости от многих деталей, которые вы не упомянули относительно ваших конкретных потребностей. Может быть, небольшой специализированный помощник, закодированный на Cython, может предложить всю необходимую вам дополнительную производительность, если уже не существует подходящей и доступной библиотеки (на C, C++, Fortran, ...), которая может быть интерфейсом для обработки этого огромного файла как тебе нужно.

Но очевидно, что здесь есть специфические проблемы — как файл данных может содержать, например, указатели, которые по своей сути являются концепцией, связанной с адресацией памяти? Возможно, вместо этого они являются «смещениями», и если да, то как именно они основаны и закодированы? Являются ли ваши потребности более продвинутыми, чем просто последовательное чтение (например, произвольный доступ), и если да, то можете ли вы выполнить первый проход «индексации», чтобы получить все смещения от начала файла до начала записи в более удобном, компактном , удобно отформатированный вспомогательный файл? (Этот двоичный файл смещений был бы естественным для array -- если только смещения не должны быть длиннее, чем array поддерживает на вашем компьютере!). Каково распределение длин и композиций записей и количества записей, составляющих «десятки гигабайт»? И т. д. и т. д.

У вас очень масштабная проблема (и, без сомнения, очень крупномасштабное аппаратное обеспечение для ее поддержки, поскольку вы упомянули, что можете легко прочитать весь файл в память, что означает 64-битный блок со многими десятками ГБ ОЗУ — вау!) , так что стоит тщательно позаботиться об оптимизации обращения с ним - но мы не можем сильно помочь с таким тщательным уходом, если мы не знаем достаточно подробностей, чтобы сделать это!-).

person Alex Martelli    schedule 17.08.2009

взгляните на модуль array, особенно на метод array.fromfile. Этот бит:

Каждая запись в файле данных имеет переменную длину.

довольно неудачно. но вы можете справиться с этим с помощью предложения try-except.

person SilentGhost    schedule 17.08.2009

Для аналогичной задачи я определил такой класс:

class foo(Structure):
        _fields_ = [("myint", c_uint32)]

создал экземпляр

bar = foo()

и сделал,

block = file.read(sizeof(bar))
memmove(addressof(bar), block, sizeof(bar))

В случае записей переменного размера вы можете использовать аналогичный метод для извлечения lenN, а затем прочитать соответствующие записи данных. Кажется тривиальным для реализации. Однако я понятия не имею, насколько быстр этот метод по сравнению с использованием pack() и unpack(), возможно, кто-то еще профилировал оба метода.

person Michael Foukarakis    schedule 17.08.2009

Для синтаксического анализа файла без чтения его в память вы можете использовать модуль bitstring.

Внутренне это использует модуль struct и bytearray, но неизменяемый объект Bits может быть инициализирован именем файла, поэтому он не будет считывать все это в память.

Например:

from bitstring import Bits

s = Bits(filename='your_file')
while s.bytepos != s.length:
    # Read a byte and interpret as an unsigned integer
    length = s.read('uint:8')
    # Read 'length' bytes and convert to a Python string
    data = s.read(length*8).bytes
    # Now do whatever you want with the data

Конечно, вы можете анализировать данные, как хотите.

Вы также можете использовать нотацию среза для чтения содержимого файла, хотя обратите внимание, что индексы будут в битах, а не в байтах, поэтому, например, s[-800:] будет последними 100 байтами.

person Scott Griffiths    schedule 17.08.2009

Что делать, если вы используете дамп файла данных в sqlite3 в памяти.

import sqlite3
sqlite3.Connection(":memory:")

Затем вы можете использовать sql для обработки данных.

Кроме того, вы можете взглянуть на генераторы (или здесь) и итераторы (или здесь и здесь).

person riza    schedule 17.08.2009
comment
Предположительно, если данные имеют переменную длину, строки не будут нормализованы для использования в базе данных. - person hughdbrown; 17.08.2009

PyTables — очень хорошая библиотека для обработки HDF5, двоичного формата, используемого в астрономии и метеорологии для обработки очень больших наборов данных:

Он работает более или менее как иерархическая база данных, где вы можете хранить несколько таблиц внутри столбцов. Посмотри на это.

person dalloliogm    schedule 17.08.2009