То, что вы пытаетесь сделать, это добавить объект (здесь List<struct_realTime>
), сериализованный с использованием MessagePackSerializer
, в файл, содержащий уже сериализованную последовательность похожих объектов,таким же образом это возможно с BinaryFormatter
, protobuf-net или Json.NET . Позже вы, вероятно, захотите иметь возможность десериализовать всю последовательность в список или массив объектов одного типа.
В вашем коде три проблемы, две простые и одна фундаментальная.
Вот простые проблемы:
На самом деле вы не пишете в fileStream
. Вместо этого выполните следующие действия:
// Append each list_temp sequentially
using (var fileStream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
MessagePackSerializer.Serialize(fileStream, list_temp);
}
Вы не пометили struct_realTime
с [MessagePackObject]
атрибутами . Это может быть реализовано, например, следующим образом:
[MessagePackObject]
public struct struct_realTime
{
[Key(0)]
public int indexNum { get; set; }
[Key(1)]
public string currentTime { get; set; }
[Key(2)]
public string currentType { get; set; }
}
Сделав это, вы теперь можете многократно сериализовать list_temp
в файл ... но вы не сможете их прочитатьпотом! Это потому, что MessagePackSerializer
, кажется, читает весь файл при десериализации корневого объекта, пропуская все дополнительные данные, добавленные в файл. Таким образом, код, подобный следующему, потерпит неудачу, поскольку из файла будет прочитан только один объект:
List<List<struct_realTime>> allItemsInFile = new List<List<struct_realTime>>();
using (var fileStream = File.OpenRead(filename))
{
while (fileStream.Position < fileStream.Length)
{
allItemsInFile.Add(MessagePackSerializer.Deserialize<List<struct_realTime>>(fileStream));
}
}
Assert.IsTrue(allItemsInFile.Count == expectedNumberOfRootItemsInFile);
Демо-скрипта # 1 здесь .
И код, подобный следующемупотерпит неудачу, потому что (первый) корневой объект в потоке - это не массив массивов объектов, а всего лишь один массив:
List<List<struct_realTime>> allItemsInFile;
using (var fileStream = File.OpenRead(filename))
{
allItemsInFile = MessagePackSerializer.Deserialize<List<List<struct_realTime>>>(fileStream);
}
Assert.IsTrue(allItemsInFile.Count == expectedNumberOfRootItemsInFile);
Демо-скрипта # 2 здесь .
Поскольку MessagePackSerializer
, кажется, не имеет возможности десериализовать несколько корневых объектов из потока, каковы ваши варианты? Во-первых, вы можете десериализовать List<List<struct_realTime>>
, добавить к нему, а затем сериализовать все обратно в файл. Предположительно, вы не хотите делать это из соображений производительности.
Во-вторых, используя спецификацию MessagePack напрямую, вы можете вручную искать начало файла для анализа и перезаписи соответствующего array 32
формат заголовка , затем найдите конец файла и используйте MessagePackSerializer
для сериализации и добавления нового элемента. Следующий метод расширения выполняет свою работу:
public static class MessagePackExtensions
{
const byte Array32 = 0xdd;
const int Array32HeaderLength = 5;
public static void AppendToFile<T>(Stream stream, T item)
{
if (stream == null)
throw new ArgumentNullException(nameof(stream));
if (!stream.CanSeek)
throw new ArgumentException("!stream.CanSeek");
stream.Position = 0;
var buffer = new byte[Array32HeaderLength];
var read = stream.Read(buffer, 0, Array32HeaderLength);
stream.Position = 0;
if (read == 0)
{
FormatArray32Header(buffer, 1);
stream.Write(buffer, 0, Array32HeaderLength);
}
else
{
var count = ParseArray32Header(buffer, read);
FormatArray32Header(buffer, count + 1);
stream.Write(buffer, 0, Array32HeaderLength);
}
stream.Position = stream.Length;
MessagePackSerializer.Serialize(stream, item);
}
static void FormatArray32Header(byte [] buffer, uint value)
{
buffer[0] = Array32;
buffer[1] = unchecked((byte)(value >> 24));
buffer[2] = unchecked((byte)(value >> 16));
buffer[3] = unchecked((byte)(value >> 8));
buffer[4] = unchecked((byte)value);
}
static uint ParseArray32Header(byte [] buffer, int readCount)
{
if (readCount < 5 || buffer[0] != Array32)
throw new ArgumentException("Stream was not positioned on an Array32 header.");
int i = 1;
///5864278/kak-poluchit-dannye-s-pryamym-poryadkom-baitov-iz-big-endian-v-c-s-pomoschy-metoda-bitconverter-toint32
//https://stackoverflow.com/a/8241127 by https://stackoverflow.com/users/23354/marc-gravell
var value = unchecked((uint)((buffer[i++] << 24) | (buffer[i++] << 16) | (buffer[i++] << 8) | buffer[i++]));
return value;
}
}
. Он может использоваться для добавления вашего list_temp
следующим образом:
// Append each entry sequentially
using (var fileStream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
MessagePackExtensions.AppendToFile(fileStream, list_temp);
}
А затем, чтобы десериализовать весь файл, выполните:
List<List<struct_realTime>> allItemsInFile;
using (var fileStream = File.OpenRead(filename))
{
allItemsInFile = MessagePackSerializer.Deserialize<List<List<struct_realTime>>>(fileStream);
}
Примечания:
Протокол MessagePack имеет 3 различных формата массива:
fixarray
хранит массив, длина которогосодержит до 15 элементов. array 16
хранит массив, длина которого составляет до (2 ^ 16) -1 элементов. array 32
хранит массив, длина которого составляет (2 ^ 32) -1 элементов.
Метод расширения требует, чтобы корневой массив был array 32
, чтобы исключить необходимость переформатирования всего массива, когда новый размер становится больше емкостиfixarray
или array 16
. Однако MessagePackSerializer
всегда будет записывать в наиболее компактный формат, поэтому добавление в коллекцию, ранее сериализованную MessagePackSerializer
, не гарантируется.
Если вы хотите использовать быстрый двоичный сериализатор, который не требует подсчета или размера массива в начале файла, тем самым поддерживая операции добавления из коробки «из коробки», рассмотрите Protobuf-сеть . Подробнее см. У меня есть один файл, и мне нужно случайным образом сериализовать несколько объектов. Как я могу в c #? и Как добавить объект в файл при сериализации с использованием c # protobuf-net? .
Для общегообзор использования этого сериализатора см. https://github.com/protobuf-net/protobuf-net#protobuf-net и Protobuf-net: неофициальное руководство . Вам нужно будет пометить ваши типы атрибутами, подобными атрибутам MessagePackSerializer
.
Демонстрационная скрипка # 3 здесь .