[英]protobuf and List<object> - how to serialize / deserialize?
[英]how to serialize / deserialize List<class object> with protobuf?
我想序列化List<ArchiveData>
但它幾乎總是失敗。 Protobuff拋出以下異常:
無效的線型; 這通常意味着您在不截斷或設置長度的情況下覆蓋了文件; 看到使用Protobuf-net,我突然得到一個關於未知線型的例外
我已閱讀帖子但仍無法找到解決方案。 我如何序列化和反序列化?
我的班級和結構:
[Serializable, ProtoContract(Name = @"Archive"), ProtoInclude(1, typeof(List<ArchiveData>))]
public partial class Archive : IExtensible
{
[ProtoMember(1, IsRequired = true, OverwriteList = true, Name = @"data", DataFormat = DataFormat.Default)]
public List<ArchiveData> data { get; set; }
public Archive()
{
data = new List<ArchiveForm.ArchiveData>();
}
private IExtension extensionObject;
IExtension IExtensible.GetExtensionObject(bool createIfMissing)
{
return Extensible.GetExtensionObject(ref extensionObject, createIfMissing);
}
}
public struct ArchiveData
{
[ProtoMember(1, IsRequired = false, OverwriteList = true, Name = @"sourcefolder", DataFormat = DataFormat.Default)]
[global::System.ComponentModel.DefaultValue("")]
public string sourcefolder { get; set; }
[ProtoMember(2, IsRequired = false, OverwriteList = true, Name = @"destinationfolder", DataFormat = DataFormat.Default)]
[global::System.ComponentModel.DefaultValue("")]
public string destinationfolder { get; set; }
[ProtoMember(3, IsRequired = false, OverwriteList = true, Name = @"period", DataFormat = DataFormat.FixedSize)]
[global::System.ComponentModel.DefaultValue((int)0)]
public int period { get; set; }
public ArchiveData(string sfolder = "", string dfolder = "", int priod = 0)
{
sourcefolder = sfolder;
destinationfolder = dfolder;
period = priod;
}
}
我用以下方法序列化:
public static void Refresh(ref Archive arc)
{
if (File.Exists(probuffile))
{
using (var fs = File.OpenRead(probuffile))
{
arc = Serializer.Deserialize<Archive>(fs);
}
}
}
我用以下方法反序列化:
public static void Update(Archive arc)
{
using (var fs = File.Create(probuffile))
{
Serializer.Serialize<Archive>(fs, arc);
fs.SetLength(fs.Position);
}
}
我用它:
Archive archive = new Archive();
//Add some ArchiveData.
Refresh(ref archive);
- - - - - - - - - - - - - - - 編輯 - - - - - - - - - - -----------
添加了此部分以獲取更多信息。 當我像下面的代碼一樣使用SerializeWithLengthPrefix / DeserializeWithLengthPrefix函數時,它每次都適用於我使用Deserialize函數的第一個類。 但是對於我使用Deserialize函數的第二個類,它返回null。
[Serializable, ProtoContract(Name = @"OptionData")]
public class OptionData : IExtensible
{
[ProtoMember(1, IsRequired = false, OverwriteList = true, Name = @"StartWithWindows", DataFormat = DataFormat.Default)]
[DefaultValue(false)]
public bool StartWithWindows { get; set; }
[ProtoMember(2, IsRequired = false, OverwriteList = true, Name = @"AutoBackup", DataFormat = DataFormat.Default)]
[DefaultValue(false)]
public bool AutoBackup { get; set; }
[ProtoMember(3, IsRequired = false, OverwriteList = true, Name = @"Speed", DataFormat = DataFormat.FixedSize)]
[DefaultValue((int)0)]
public int Speed { get; set; }
private IExtension extensionObject;
IExtension IExtensible.GetExtensionObject(bool createIfMissing)
{
return Extensible.GetExtensionObject(ref extensionObject, createIfMissing);
}
}
public static void Update(OptionData op)
{
using (var fs = File.Create(probuffile))
{
Serializer.SerializeWithLengthPrefix(fs, op, PrefixStyle.Base128, 3);
}
}
public static void Update(Archive arc)
{
using (var fs = File.Create(probuffile))
{
Serializer.SerializeWithLengthPrefix<Archive>(fs, arc, PrefixStyle.Base128, 2);
}
}
public static void Refresh(ref OptionData op)
{
if (File.Exists(probuffile))
{
using (var fs = File.OpenRead(probuffile))
{
op = Serializer.DeserializeWithLengthPrefix<OptionData>(fs, PrefixStyle.Base128, 3);
}
}
}
public static void Refresh(ref Archive arc)
{
if (File.Exists(probuffile))
{
using (var fs = File.OpenRead(probuffile))
{
arc = Serializer.DeserializeWithLengthPrefix<Archive>(fs, PrefixStyle.Base128, 2);
}
}
}
我很樂意提供幫助,但我很難讓它失敗。 你說“但它幾乎總是失敗”,但是下面的可運行的控制台exer工作正常,並編寫了大量不同大小的數據:
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.IO;
static class P
{
static void Main()
{
var random = new Random(12345);
// start with 100
var archive = CreateData(random, 100);
Update(archive);
Refresh(ref archive);
// make it bigger
archive = CreateData(random, 200);
Update(archive);
Refresh(ref archive);
// make it smaller
archive = CreateData(random, 50);
Update(archive);
Refresh(ref archive);
// go wild
for (int i = 0; i < 1000; i++)
{
archive = CreateData(random, random.Next(0, 500));
Update(archive);
Refresh(ref archive);
}
}
static Archive CreateData(Random random, int dataCount)
{
var archive = new Archive();
var data = archive.data;
for (int i = 0; i < dataCount; i++)
{
data.Add(new ArchiveData
{
period = random.Next(10000),
sourcefolder = CreateString(random, 50),
destinationfolder = CreateString(random, 50)
});
}
return archive;
}
private static unsafe string CreateString(Random random, int maxLength)
{
const string Alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
int len = random.Next(maxLength + 1);
char* chars = stackalloc char[len];
for (int i = 0; i < len; i++)
{
chars[i] = Alphabet[random.Next(Alphabet.Length)];
}
return new string(chars, 0, len);
}
static string probuffile = "my.bin";
public static void Refresh(ref Archive arc)
{
if (File.Exists(probuffile))
{
using (var fs = File.OpenRead(probuffile))
{
arc = Serializer.Deserialize<Archive>(fs);
Console.WriteLine("Read: {0} items, {1} bytes", arc.data.Count, fs.Length);
}
}
}
public static void Update(Archive arc)
{
using (var fs = File.Create(probuffile))
{
Serializer.Serialize<Archive>(fs, arc);
fs.SetLength(fs.Position);
Console.WriteLine("Wrote: {0} items, {1} bytes", arc.data.Count, fs.Length);
}
}
}
[Serializable, ProtoContract(Name = @"Archive"), ProtoInclude(1, typeof(List<ArchiveData>))]
public partial class Archive : IExtensible
{
[ProtoMember(1, IsRequired = true, OverwriteList = true, Name = @"data", DataFormat = DataFormat.Default)]
public List<ArchiveData> data { get; set; }
public Archive()
{
data = new List<ArchiveData>();
}
private IExtension extensionObject;
IExtension IExtensible.GetExtensionObject(bool createIfMissing)
{
return Extensible.GetExtensionObject(ref extensionObject, createIfMissing);
}
}
[ProtoContract]
public struct ArchiveData
{
[ProtoMember(1, IsRequired = false, OverwriteList = true, Name = @"sourcefolder", DataFormat = DataFormat.Default)]
[global::System.ComponentModel.DefaultValue("")]
public string sourcefolder { get; set; }
[ProtoMember(2, IsRequired = false, OverwriteList = true, Name = @"destinationfolder", DataFormat = DataFormat.Default)]
[global::System.ComponentModel.DefaultValue("")]
public string destinationfolder { get; set; }
[ProtoMember(3, IsRequired = false, OverwriteList = true, Name = @"period", DataFormat = DataFormat.FixedSize)]
[global::System.ComponentModel.DefaultValue((int)0)]
public int period { get; set; }
public ArchiveData(string sfolder = "", string dfolder = "", int priod = 0)
{
sourcefolder = sfolder;
destinationfolder = dfolder;
period = priod;
}
}
我猜你的真實代碼和上面的例子之間的區別是:這也是問題的原因。 如果你幫助找到不同的東西,我會非常樂意為你提供合理的幫助。
作為次要注意事項:使用Create
時實際上不需要設置長度,因為這顯然是“丟棄任何現有數據”。 你需要擔心的時間長短的主要時間是當人們使用OpenWrite
寫在現有的文件,然后寫入的數據較少比已經在那里了。 但是在Create
之后顯式設置長度沒有問題
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.