2017-03-28 9 views
1

List<ArchiveData>をシリアライズしたいですが、ほとんどいつも失敗します。 Protobuff throw例外:protobufでList <class object>をシリアライズ/デシリアライズする方法は?

ワイヤタイプが無効です。これは通常、長さを切り捨てたり設定したりせずにファイル を上書きしたことを意味します。 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関数を使用する2番目のクラスの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

申し訳ありません。私の悪い。私はクラスを書くのを忘れた。 –

+0

編集:それらは同じファイルにありますか?または別のファイルですか?同じファイルから連続する2つのものを読みたい場合は、単一の 'File.OpenRead'セッションでそれらを連続して読み込む必要があります。それ以外の場合は、 'File.OpenRead'を呼び出すたびにファイルの先頭に戻り、間違ったデータを読み込みます。あなたは 'Update'と' Refresh'がどのように使われているかを示していないので、私は100%確実ではありません。繰り返しますが、私の答えのように、実際に問題が発生していることを示す**完全実行可能な**コード( 'Main()'メソッドなど)を投稿するのが最善の方法です。 –

答えて

0

私は喜んで助けてくれるが、失敗するのは苦労している。あなたは言う、「それはほとんど常に失敗」が、次の実行可能なコンソール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 = "abcdefghijklmnopqrstuvwxyz"; 
     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

  0

私は最終的にいつ失敗するかを理解しています(OptionDataという別のシリアライズ可能なクラスがあります)。 1)私はOptionDataをシリアライズ/デシリアライズするだけで正しく動作します。 2)私はシリアル化/アーカイブだけを逆シリアル化、それは正常に動作します。しかし3)OptionDataとArchiveの両方がシリアル化されている間にアーカイブを非直列化すると、Archiveは失敗し、OptionDataは正常に動作します。 29 3月. 172017-03-29 10:35:20

+1

@BurakKocamanあなたが私にそれを見てもらいたいなら、いくつかのコードが必要です。推測すると、同じストリームで連続してシリアル化していますか(つまり、 'Serialize'への2回の呼び出し)ですか?もしそうなら、 '* WithLengthPrefix'メソッドを使う必要があります。しかし、それを簡単に修正するには、2つのアイテムをメンバ1/2、すなわち '[ProtoContract] class MyRoot {[ProtoMember(1)] publicアーカイブアーカイブ{get; set;} [ ProtoMember(2)] public OptionDataオプション{get; set;}} ' 29 3月. 172017-03-29 11:33:42

  0

回答ありがとうございます。 WithLengthPrefixを使用しようとしましたが、動作しなかったときに別の解決策を探すべきだと思いました。しかし、あなたの答えの後、私はそれを間違って使用したと確信しています。 WithLengthPrefixを正しく動作させるまで使用してみます:Dもう一度ありがとうございます。 29 3月. 172017-03-29 13:30:08

  0

@BurakKocamanあなたが持っているものを修正したいなら、私はそれをすることができます - しかし、私は失敗したコードを見る必要があります 29 3月. 172017-03-29 13:35:49

  0

私は投稿を編集し、あなたが要求したコードを追加します。 29 3月. 172017-03-29 16:55:19


+0

私は最終的にいつ失敗するかを理解しています(OptionDataという別のシリアライズ可能なクラスがあります)。 1)私はOptionDataをシリアライズ/デシリアライズするだけで正しく動作します。 2)私はシリアル化/アーカイブだけを逆シリアル化、それは正常に動作します。しかし3)OptionDataとArchiveの両方がシリアル化されている間にアーカイブを非直列化すると、Archiveは失敗し、OptionDataは正常に動作します。 –

+1

@BurakKocamanあなたが私にそれを見てもらいたいなら、いくつかのコードが必要です。推測すると、同じストリームで連続してシリアル化していますか(つまり、 'Serialize'への2回の呼び出し)ですか?もしそうなら、 '* WithLengthPrefix'メソッドを使う必要があります。しかし、それを簡単に修正するには、2つのアイテムをメンバ1/2、すなわち '[ProtoContract] class MyRoot {[ProtoMember(1)] publicアーカイブアーカイブ{get; set;} [ ProtoMember(2)] public OptionDataオプション{get; set;}} ' –

+0

回答ありがとうございます。 WithLengthPrefixを使用しようとしましたが、動作しなかったときに別の解決策を探すべきだと思いました。しかし、あなたの答えの後、私はそれを間違って使用したと確信しています。 WithLengthPrefixを正しく動作させるまで使用してみます:Dもう一度ありがとうございます。 –

関連する問題