2010-11-28 122 views
5

我正在嘗試執行對象的自定義序列化/反序列化以及使用DeflateStreams壓縮/解壓縮序列化的數據。我原本是爲了處理更復雜的對象而做的,但是爲了試圖找出問題而做了一些嘗試,但是由於它仍然存在,它變得更加令人費解。這裏是要序列化的類/反序列化:C#自定義序列化/反序列化與DeflateStreams

[Serializable] 
    public class RandomObject : ISerializable 
    { 
     public String Name { get; set; } 
     public String SavePath { get; set; } 

     public RandomObject() 
     { 
     } 

     public RandomObject(String name, String savepath) 
     { 
      Name = name; 
      SavePath = savepath; 
     } 

     public RandomObject(SerializationInfo info, StreamingContext context) 
      : this(info.GetString("name"), info.GetString("savepath")) 
     { 
     } 
     [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] 
     public void GetObjectData(SerializationInfo info, StreamingContext context) 
     { 
      info.AddValue("name", Name); 
      info.AddValue("savepath", SavePath); 
     } 
    } 

這裏是應該序列化(這似乎工作)代碼:

BinaryFormatter bf = new BinaryFormatter(); 
      using (MemoryStream ms = new MemoryStream()) 
      { 
       bf.Serialize(ms, profile); 
       using (DeflateStream ds = new DeflateStream(ms, CompressionMode.Compress)) 
       { 
        try 
        { 
         using (FileStream fs = File.Create(path)) 
         { 
          ds.Flush(); 
          Miscellaneous.CopyStream(ds.BaseStream, fs); 
          fs.Flush(); 
          fs.Close(); 
         } 
        } 
        catch (IOException e) 
        { 
         MessageBox.Show(e.Message); 
         success = false; 
        } 
        ds.Close(); 
       } 
       ms.Close(); 
      } 

,這裏是反序列化:

RandomObject profile = null; 
       using (FileStream fs = File.OpenRead(path)) 
       { 
        using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Decompress)) 
        { 
         BinaryFormatter bf = new BinaryFormatter(); 
         ds.Flush(); 

         using (MemoryStream ms = new MemoryStream()) 
         { 
          Miscellaneous.CopyStream(ds.BaseStream, ms); 
          profile = bf.Deserialize(ms) as RandomObject; 
          profile.SavePath = path; 
          ms.Close(); 
         } 
         ds.Close(); 
        } 
        fs.Close(); 
       } 

現在,解決問題。反序列化拋出一個SerializationException,並帶有消息{「No map for object'201326592'。」}我不知道如何解決問題或弄清究竟是什麼導致了問題。當我在同一個MemoryStream上運行BinaryFormatter的Serialize和Deserialize方法時,非常基本的序列化工作。

我試圖從兩種方法中刪除DeflateStream的東西,但它仍然是同樣的問題。當我看到MSDN和其他地方的示例時,它看起來像我做得很恰當,並且使用Google搜尋異常消息不會給出任何有意義的結果(或者我可能只是在搜索時遇到不好的情況)。

PS。正如你所看到的,我使用Miscellaneous.CopyStream(src,dest),它是一個基本的流複製器,因爲我無法獲得src.CopyTo(dest)的功能,所以我們也歡迎任何提示。

下面是一個鏈接到整個VS2010項目,如果你想更仔細地看: http://www.diredumplings.com/SerializationTesting.zip

UPDATE:

The_Smallest:我試着用你貼在壓縮方法我係列化:

BinaryFormatter bf = new BinaryFormatter(); 
      using (MemoryStream stream = new MemoryStream()) 
      { 
       bf.Serialize(stream, profile); 

       byte[] array = Compress(stream); 

       using (MemoryStream ms = new MemoryStream(array)) 
       { 
        using (FileStream fs = File.Create(path)) 
        { 
         ms.WriteTo(fs); 
         fs.Flush(); 
        } 
       } 
      } 

然而,這似乎給我,我和srcStream.CopyTo(destStream)早前曾同樣的問題,這是它似乎沒有寫入流中。當我嘗試將它保存到磁盤時,結果是一個0 kb的文件。有任何想法嗎?

Pieter:我從反序列化方法中刪除了MemoryStream,它看起來具有和以前相同的功能。但是我不確定如何按照您的建議來實現序列化。這是你想到的嗎?

BinaryFormatter bf = new BinaryFormatter(); 

      using (FileStream fs = File.Create(path)) 
      { 
       using (DeflateStream ds = new DeflateStream(fs, CompressionMode.Compress)) 
       { 
        bf.Serialize(ds, profile); 
        fs.Flush(); 
        ds.Close(); 
       } 
       fs.Close(); 
      } 

感謝你們倆!

+0

什麼是Stream.Copy的問題?它爲什麼會失敗? – 2010-11-28 17:03:16

+0

無論我如何使用它,目標流總是空的,可能只是我做了一些愚蠢的事情。 – vesz 2010-11-28 18:19:14

回答

1

我下載了你的例子,並在那裏挖了一點。請參閱下面的項目變化:

  1. 在Loader.cs更換LoadFromFile
private static RandomObject LoadFromFile(string path) 
{ 
    try 
    { 
    var bf = new BinaryFormatter(); 
    using (var fileStream = File.OpenRead(path)) 
    using (var decompressed = new MemoryStream()) 
    { 
     using (var deflateStream = new DeflateStream(fileStream, CompressionMode.Decompress)) 
     deflateStream.CopyTo(decompressed); 

     decompressed.Seek(0, SeekOrigin.Begin); 
     var profile = (RandomObject)bf.Deserialize(decompressed); 
     profile.SavePath = path; 
     return profile; 
    } 
    } 
    catch (IOException e) 
    { 
    MessageBox.Show(e.Message); 
    return null; 
    } 
} 
 
  1. 在Saver.cs更換Save如下:
public static bool Save(RandomObject profile, String path) 
{ 
    try 
    { 
     var bf = new BinaryFormatter(); 
     using (var uncompressed = new MemoryStream()) 
     using (var fileStream = File.Create(path)) 
     { 
     bf.Serialize(uncompressed, profile); 
     uncompressed.Seek(0, SeekOrigin.Begin); 

     using (var deflateStream = new DeflateStream(fileStream, CompressionMode.Compress)) 
      uncompressed.CopyTo(deflateStream); 
     } 
     return true; 
    } 
    catch (IOException e) 
    { 
     MessageBox.Show(e.Message); 
     return false; 
    } 
} 
1

您應該序列化爲DeflateStream,而不是基礎流(MemoryStream)。

序列化:從File.Create開始。然後在該流的附近創建DeflateStream。然後到DefaulteStream,序列化你的對象。

對於反序列化:請勿創建MemoryStream並直接從DeflateStream反序列化。我相信不需要添加MemoryStream。但是,如果直接寫入/直接從文件流中讀取時出現問題,只需更改序列化例程以寫入DeflateStream而不是MemoryStream

這應該解決您的問題。

+0

MemoryStream的原因是,因爲我可以告訴我只能讀取DeflateStream,而不是寫入或尋找它。我會嘗試上面的更改,看看它是否有效,謝謝。 – vesz 2010-11-28 17:13:17

+0

我在問題中發佈了一個更新到您的解決方案,我仍然不知道如何讓它工作。謝謝你的回覆! – vesz 2010-11-28 18:11:03

1

有溪流中的邏輯錯誤,在壓縮的同時,你應該寫CompressStream,其中寫到MemoryStream的,在這之後,你將有結果的MemoryStream(不CompressStream) 下面是例子,如何壓縮和解壓縮字節

private static byte[] Compress(Stream stream) 
    { 
     using (var resultStream = new MemoryStream()) 
     { 
      using (var gzipStream = new DeflateStream(resultStream, CompressionMode.Compress)) 
       stream.CopyTo(gzipStream); 
      return resultStream.ToArray(); 
     } 
    } 

    private static byte[] Decompress(byte[] bytes) 
    { 
     using (var readStream = new MemoryStream(bytes)) 
     using (var resultStream = new MemoryStream()) 
     { 
      using (var gzipStream = new DeflateStream(readStream, CompressionMode.Decompress)) 
       gzipStream.CopyTo(resultStream); 
      return resultStream.ToArray(); 
     } 
    }