您要做的是将使用MessagePackSerializer 序列化的对象(此处为List<struct_realTime>)追加到包含已序列化的类似对象序列的文件中,方式相同可以使用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] attributes。这可以实现,例如如下:
[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 here.
并且像下面这样的代码会失败,因为流中的(第一个)根对象不是对象数组的数组,而只是一个数组:
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 here.
MessagePackSerializer 似乎缺乏从流中反序列化多个根对象的能力,您有什么选择?首先,您可以反序列化 List<List<struct_realTime>>,附加到它,然后将整个内容序列化回文件。出于性能原因,您可能不想这样做。
其次,直接使用MessagePack specification,你可以手动寻找到文件的开头解析并重写一个合适的array 32 format header,然后寻找到文件的末尾并使用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;
//https://*.com/questions/8241060/how-to-get-little-endian-data-from-big-endian-in-c-sharp-using-bitconverter-toin
//https://*.com/a/8241127 by https://*.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);
}
注意事项:
演示小提琴#3 here.