Как эффективно читать двоичные данные из файлов, которые имеют сложную структуру в C ++ - PullRequest
3 голосов
/ 18 ноября 2011

Я пишу фрагмент кода для чтения в нескольких ГБ данных, охватывающих несколько файлов, с использованием C ++ IOStreams, который я выбрал по сравнению с C API по ряду конструктивных причин, с которыми я не буду утомлять вас.Поскольку данные создаются отдельной программой на той же машине, где будет выполняться мой код, я уверен, что такие проблемы, как проблемы с порядком байтов, по большей части можно игнорировать.

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

Мой вопрос связан с тем, как сделать это эффективно - я уверен, что мой процесс будет ограничен по IO, поэтому мой инстинктзаключается в том, что вместо чтения данных в маленьких блоках, таких как следующий подход

std::vector<int> buffer;
buffer.reserve(500);
file.read( (char*)&buffer[0], 500 * sizeof(int));

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

  • Учитывая, что это может означать чтение в массиве char * или std :: vector, как бы вы лучше всего конвертировали этот массив в формат данных, необходимый для правильного представленияфайловая структура?
  • Мои предположения неверны?

Я знаю, что очевидным ответом будет попытка, а затем профилирование позже, и профиль я, безусловно, буду.Но этот вопрос больше касается того, как правильно выбрать подход с самого начала - своего рода оптимизация «выбери правильный алгоритм», а не тот вид оптимизаций, который я мог бы предусмотреть после выявления узких мест позже!

Мне будут интересны предложенные ответы - я, как правило, могу найти ответы только для относительно простых двоичных файлов, для которых подходит вышеуказанный подход.Моя проблема в том, что основная часть двоичных данных условно структурирована по числам в заголовке файла (даже заголовок отформатирован таким образом!), Поэтому мне нужно иметь возможность обрабатывать файл немного более тщательно.

Заранее спасибо.

РЕДАКТИРОВАТЬ: Некоторые комментарии по поводу отображения памяти - выглядит хорошо, но не уверен, как это сделать, и все, что я прочитал, говорит мне, что это не такт портативный.Я заинтересован в том, чтобы попробовать mmap, но также и в более портативных решениях (если есть!)

Ответы [ 4 ]

6 голосов
/ 18 ноября 2011

Используйте 64-битную ОС и карту памяти для файла. Если вам также требуется поддержка 32-разрядной ОС, используйте уровень совместимости, который отображает фрагменты файла по мере необходимости.

В качестве альтернативы, если вам всегда нужны объекты в порядке файлов, просто напишите вменяемый синтаксический анализатор для обработки объектов в виде фрагментов. Как это:

1) Чтение 512 КБ файла.

2) Извлекать как можно больше объектов из данных, которые мы читаем.

3) Считайте столько байтов, сколько необходимо, чтобы заполнить буфер до 512 КБ. Если мы вообще не читаем байты, остановитесь.

4) Перейти к шагу 3.

1 голос
/ 18 ноября 2011

Полагаю, у вас уже достаточно для начала, отображение памяти, безусловно, является изящной идеей, если у вас достаточно ОЗУ. Остальное читается большими кусками.

Как только данные доступны в памяти целым файлом или большим фрагментом, самый простой способ прочитать это:

  • определить соответствующую структуру
  • создать указатель на соответствующее смещение в памяти, куда загружаются данные
  • reinterpret_cast указатель на указатель типа "соответствующая структура" или массив соответствующей структуры.

Вы можете использовать # pragmas , чтобы при необходимости указать размер упаковки / порядок и т. Д. Но опять же это будет зависеть от ОС / компилятора.

1 голос
/ 18 ноября 2011

Вы можете mmap некоторые сегменты файла (или весь файл, по крайней мере, на 64-битной машине).Возможно использовать madvise и (в отдельном потоке) readahead

0 голосов
/ 18 ноября 2011

Хорошо, хорошо, заголовок переменной длины, но вы должны начать где-нибудь.Если сначала нужно прочитать весь файл, он может стать немного грязным.Весь файл может быть представлен структурой, содержащей заголовок до некоторого дескриптора длины, а затем байтовый массив - вы можете начать там.Когда у вас есть длина заголовка, вы можете установить указатель / длину для массива записей заголовка, а затем выполнить их итерацию и так установить указатель / длину для массива структур содержимого файла и т. Д. И т. Д.

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

Противный.Мне не очень нравится мой собственный дизайн: (

Кто-нибудь получил идею получше, кроме переписывания «отдельной программы» для использования базы данных или XML или чего-то еще?

...