c # двоичная сериализация в файл построчно или как разделить

#c# #.net #json #file #serialization

#c# #.net #json #файл #сериализация

Вопрос:

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

Я думал, что могу сохранять объект в строке. но когда я открыл файл в блокноте, он был длиннее строки. Это была не прокрутка. Как я могу сохранить двоичный сериализованный объект в строке?

Я знаю, что могу использовать разделитель после каждого объекта, чтобы при чтении их обратно в приложение я мог знать конец объекта. Ну, согласно теории информации, это увеличивает размер данных (книга Sipser).

Какой наилучший алгоритм для создания разделителя, который не нарушал бы информацию?

Вместо двоичной сериализации? Как вы думаете, формат JSon более осуществим? могу ли я сохранить объект в формате json, построчно?

Кроме того, сериализация / десериализация приводит к накладным расходам и снижает производительность. Будет ли Json быстрее?

идеи?

Спасибо.

Спасибо.

Ответ №1:

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

 public class Test
    {

        public void testSerialize()
        {
            TestObj obj = new TestObj();
            obj.str = "Some String";
            IFormatter formatter = new BinaryFormatter();
            Stream stream = new FileStream("MyFile.bin", FileMode.Create, FileAccess.Write, FileShare.None);
            formatter.Serialize(stream, obj);
            formatter.Serialize(stream, 1);
            formatter.Serialize(stream, DateTime.Now);
            stream.Close();
        }

        public void TestDeserialize()
        {
            Stream stream = new FileStream("MyFile.bin", FileMode.Open, FileAccess.Read, FileShare.None);
            IFormatter formatter = new BinaryFormatter();
            TestObj obj = (TestObj)formatter.Deserialize(stream);
            int obj2 = (int)formatter.Deserialize(stream);
            DateTime dt = (DateTime)formatter.Deserialize(stream);
            stream.Close();
        }
    }

    [Serializable]
    class TestObj
    {
        public string str = "1";
        int i = 2;
    }
  

Комментарии:

1. интересно. я должен попробовать это.

2. хорошо, вопрос: откуда вы знаете, сколько объектов в файле? как вы планируете заполнить их все?

3. на самом деле вы не можете знать, сколько, потому что внутри могут находиться объекты разного типа, однако, если вы знаете, что внутри находятся только объекты типа X, вы можете десериализовать в цикле, помещая объекты в список, и перехватить исключение сериализации при передаче end потока, что означает, что вы завершили .. но это чревато ошибками, поскольку вы должны полагаться на сообщение об исключении «Конец потока, обнаруженный до завершения синтаксического анализа»

4. @user177883 Либо убедитесь, что первый объект, который вы сериализуете, является заголовком (например, int ), содержащим количество объектов, либо проверьте EOF после чтения каждого объекта.

5. да, хорошо, что 1, вы могли бы поместить количество в первую позицию 🙂

Ответ №2:

Что ж,

Сериализация / десериализация приводит к накладным расходам, будет ли Json быстрее?

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

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

Если вы используете разделитель, который .Платформа сетевой сериализации выдает, тогда, очевидно, вам будет сложно (если не невозможно) правильно определить, где разрывы между объектами приводят к сбоям десериализации.

Почему именно вы хотите поместить каждый объект в отдельную строку?

Комментарии:

1. таким образом, я могу читать объекты построчно, и мне не нужен разделитель.

2. @user177883 Почему бы вместо этого просто не сериализовать массив объектов?

3. это может сработать. хорошая идея. Должен ли я хранить все объекты в списке, а затем сериализовать список в файл?

4. @user177883 Вот что я, вероятно, сделал бы, или если вы хотите, чтобы aovid десериализовал весь список сразу, тогда сделайте то, что предлагает Марино.

5. @user177883 Вы могли бы сначала сериализовать объект заголовка (например, и int ) в файл, который содержит количество сохраненных объектов — при чтении просто убедитесь, что вы сначала извлекаете / десериализуете int из стека, и тогда вы будете знать, сколько объектов нужно десериализовать. Вы также можете проверять, дошли ли вы до конца файла, когда заканчиваете десериализацию (при условии, что вы не сериализуете никаких дополнительных данных в конце файла).

Ответ №3:

Двоичная сериализация сохраняет данные в произвольных байтах; эти байты могут включать символы новой строки.

Вы просите использовать новые строки в качестве разделителей. Новые строки ничем не отличаются от других разделителей; они также увеличат размер данных.

Ответ №4:

Вы также могли бы создать ArrayList и добавить в него объекты, а затем сериализовать его 😉

 ArrayList list = new ArrayList();
list.Add(1);
list.Add("Hello World");
list.Add(DateTime.Now);

BinaryFormatter bf = new BinaryFormatter();

FileStream fsout = new FileStream("file.dat", FileMode.Create);
bf.Serialize(fsout, list);
fsout.Close();

FileStream fsin = new FileStream("file.dat", FileMode.Open);
ArrayList list2 = (ArrayList)bf.Deserialize(fsin);

fsin.Close();

foreach (object o in list2)
   Console.WriteLine(o.GetType());