C # сериализует большой массив на диск - PullRequest
3 голосов
/ 05 октября 2010

У меня есть очень большой график, хранящийся в одномерном массиве (около 1,1 ГБ), который я могу хранить в памяти на моей машине под управлением Windows XP с 2 ГБ оперативной памяти и 2 ГБ виртуальной памяти.Я могу сгенерировать весь набор данных в памяти, однако, когда я пытаюсь сериализовать его на диск, используя BinaryFormatter, размер файла достигает примерно 50 МБ, а затем выдает исключение нехватки памяти.Код, который я использую для написания этого кода, тот же, который я использую среди всех моих небольших проблем:

StateInformation[] diskReady = GenerateStateGraph();
BinaryFormatter bf = new BinaryFormatter();
using (Stream file = File.OpenWrite(@"C:\temp\states.dat"))
{
    bf.Serialize(file, diskReady);
}

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

У меня действительно есть 3 вопроса:

  1. Есть ли более надежный способ записи большого набора данных на диск.Я полагаю, вы можете определить большой размер, например, когда размер набора данных приближается к объему доступной памяти, хотя я не уверен, насколько это точно.центрический подход?

  2. Может кто-нибудь указать мне на литературу о чтении частей большого набора данных из файла на диске в C #?

Ответы [ 3 ]

1 голос
/ 05 октября 2010

Пишите записи в файл самостоятельно.Одно простое решение будет выглядеть следующим образом:

StateInformation[] diskReady = GenerateStateGraph();
BinaryFormatter bf = new BinaryFormatter();
using (Stream file = File.OpenWrite(@"C:\temp\states.dat"))
{
  foreach(StateInformation si in diskReady)
    using(MemoryStream ms = new MemoryStream())
    {
      bf.Serialize(ms, diskReady);
      byte[] ser = ms.ToArray();
      int len = ser.Length;
      file.WriteByte((byte) len & 0x000000FF);
      file.WriteByte((byte) (len & 0x0000FF00) >> 8);
      file.WriteByte((byte) (len & 0x00FF0000) >> 16);
      file.WriteByte((byte) (len & 0x7F000000) >> 24);
      file.Write(ser, 0, len);
    }
}

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

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

1 голос
/ 05 октября 2010

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

Это может быть не практично в зависимости от того, насколько сложен ваш класс StateInformation , но если он достаточно прост, вы можете писать / читать двоичные данные вручную, используя BinaryReader и BinaryWriter вместо.Это позволит вам читать / записывать большинство типов значений непосредственно в поток в ожидаемом заранее определенном порядке, определяемом вашим кодом.

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

0 голосов
/ 05 октября 2010

Что содержится в StateInformation? Это класс? структура

Если вас просто беспокоит простой в использовании формат контейнера, который легко сериализуется на диск - создайте типизированный DataSet, сохраните информацию в DataSet, затем используйте метод WriteXml () в DataSet сохранить его на диск. Затем вы можете создать пустой DataSet, а затем использовать ReadXml () для загрузки содержимого обратно в память.

Если StateInformation находится в структуре с типами значений, вы можете посмотреть на MemoryMappedFile для хранения / использования содержимого массива, обращаясь к файлу напрямую, рассматривая его как память. Этот подход немного сложнее, чем DataSet, но имеет свой собственный набор преимуществ.

...