我想序列化List<ArchiveData>
,但它几乎总是失败。 Protobuff抛出以下异常:
无效的线型;这通常意味着你覆盖了一个文件 没有截断或设定长度;看到 Using Protobuf-net, I suddenly got an exception about an unknown wire-type
我已阅读该帖但仍无法找到解决方案。我如何序列化和反序列化?
我的班级和结构:
[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);
}
}
}
答案 0 :(得分:0)
我很乐意提供帮助,但我正在努力让它失败。你说&#34;但它几乎总是失败&#34;,但是下面的可运行的控制台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
时,您实际上并不需要设置长度,因为这显然是&#34;丢弃任何现有数据&#34;。您需要担心长度的主要时间是人们使用OpenWrite
来覆盖现有文件,然后编写 less 数据。但是{em>问题并没有明确设置Create
之后的长度