Чтение из огромного MemoryStream в C#

Я использую BinaryReader (MemoryStream(MyByteArray)) для чтения записей переменного размера и обработки их всех в памяти. Это хорошо работает, пока мой байтовый поток, который находится в массиве, имеет размер менее 1,7 ГБ. После этого (что является максимальным размером целого числа в моей 64-битной системе) вы не можете создать массив байтов большего размера, хотя реальной памяти у меня достаточно. Поэтому мое решение состояло в том, чтобы прочитать поток байтов и разделить его на несколько массивов байтов.

Однако теперь я не могу «читать» границы массива байтов, и, поскольку мои данные имеют переменный формат, я не могу гарантировать, что массивы байтов всегда заканчиваются на всей записи.

Это должно быть распространенной проблемой для людей, обрабатывающих очень большие наборы данных, которым все еще нужна скорость.

Как мне справиться с этой проблемой?


person ManInMoon    schedule 06.09.2010    source источник
comment
Вы должны предотвратить загрузку массива байтов такого размера в память для начала. Разве нельзя реализовать потоковое решение, в котором вы загружаете только части массива в память (буфер)? Вам нужен произвольный доступ к этим байтам? Или вы можете использовать прямое решение, в котором вы можете читать поток от начала до конца во время его обработки (и не оглядываясь назад). Откуда берется этот массив байтов? Файл, веб-сервис, ...?   -  person Ronald Wildenberg    schedule 06.09.2010


Ответы (2)


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

Вы пробовали что-то вроде этого:

var stream = new FileStream("data", 
    FileMode.Open, 
    FileAccess.Read, 
    FileShare.Read, 
    16 * 1024, 
    FileOptions.SequentialScan)

var reader = new BinaryReader(stream);

Если ваши данные находятся в файле и вы можете использовать .NET 4.0, рассмотрите возможность использования MemoryMappedFile.

Затем вы можете использовать MemoryMappedViewStream для получить поток или использовать MemoryMappedViewAccessor для получить BinaryReader-подобный интерфейс.

person Rasmus Faber    schedule 06.09.2010
comment
Да. Я пробовал это - к сожалению, MemoryMappedFiles действительно очень медленные. - person ManInMoon; 06.09.2010

Для чрезмерно больших потоков вы не должны пытаться сбрасывать их в MemoryStream — вместо этого используйте такие вещи, как FileStream, и общайтесь напрямую с диском. Встроенной буферизации обычно достаточно, или вы можете настроить ее с помощью таких вещей, как BufferedStream (но мне редко приходилось это делать, но я обычно добавляю свой собственный буфер обработки данных).

Вы также можете рассмотреть такие вещи, как сжатие или плотно упакованные данные, а также сериализаторы, предназначенные для работы с потоковыми записями, а не для создания всего графика сразу (хотя, поскольку вы упомянули BinaryReader, вы, возможно, уже делаете это вручную , так что это может быть не проблема).

person Marc Gravell    schedule 06.09.2010
comment
Да. Он сжат - очень эффективно, и я десериализую его с помощью своей собственной логики. Но чтение с диска слишком медленное. Все - я использую параллельную обработку этого огромного файла данных, и его наличие на диске может вызвать всевозможные разногласия. - person ManInMoon; 06.09.2010
comment
Использование memoryStrea, все в памяти - отлично работает для меня, за исключением того, что теперь мои данные переросли этот произвольный максимальный размер массива байтов. - person ManInMoon; 06.09.2010
comment
Я надеюсь, что вы закончили читать свои 300 электронных писем, иначе никакого десерта (ТАК) для вас! - person John K; 06.09.2010
comment
@ManInMoon - тогда (а также с учетом вашего комментария к файлам с отображением памяти) вам придется разбить данные на несколько байтовых массивов и либо написать свою собственную реализацию потока с поддержкой памяти, либо разделить ее в подходящих точках, которые позволяют несколько независимых потоков памяти. - person Marc Gravell; 06.09.2010
comment
@Marc Gravell: я знаю, что это старый вопрос, но я также читаю большие блоки памяти в MemoryStream. Я рассматриваю возможность изменения его на MemoryMappedViewStream (с базовым MemoryMappedFile). Меня беспокоила производительность, основанная на скорости ОЗУ и скорости диска, поэтому мне интересно, основан ли ваш ответ больше на размере потока, а не на скорости потока . (Если вы предпочитаете, чтобы я опубликовал это как новый вопрос, я могу.) - person MrWuf; 25.05.2012
comment
@MrWuf действительно зависит от размера; вы должны иметь возможность обращаться к отображаемым файлам последовательно по частям, а не загружать большую часть в поток памяти; решать вам - person Marc Gravell; 25.05.2012
comment
@MarcGravell +1 Спасибо за помощь! Я собираюсь попробовать поток в обоих направлениях и получить для них некоторые контрольные данные. - person MrWuf; 26.05.2012