5

我正在尝试对对象进行自定义序列化/反序列化以及使用 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 和其他地方的示例时,看起来我做得恰到好处,并且谷歌搜索异常消息并没有给出任何有意义的结果(或者我可能只是不擅长搜索)。

PS。如您所见,我使用 Miscellaneous.CopyStream(src, dest) 这是一个基本的流复制器,因为我根本无法让 src.CopyTo(dest) 工作,因此也欢迎任何提示。

如果您想更仔细地查看它,下面是整个 VS2010 项目的链接: http ://www.diredumplings.com/SerializationTesting.zip

更新:

The_Smallest:我尝试使用您在我的序列化中发布的 Compress 方法:

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();
            }

感谢你们俩!

4

3 回答 3

1

您应该序列化为DeflateStream,而不是基本 ( MemoryStream) 流。

对于序列化:以File.Create. 然后围绕该流,创建DeflateStream. 然后到DefaulteStream, 序列化你的对象。

对于反序列化:不要MemoryStream直接从DeflateStream.

我相信没有必要添加MemoryStream. 但是,如果您确实在直接写入/直接从文件流中读取时遇到问题,只需将序列化例程更改为写入DeflateStream而不是MemoryStream.

那应该可以解决您的问题。

于 2010-11-28T17:01:41.333 回答
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();
        }
    }
于 2010-11-28T17:10:50.223 回答
1

我下载了你的例子并在那里挖掘了一点。请参阅以下项目的更改:

  1. LoadFromFile在 Loader.cs 中替换
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;
    }
}
于 2010-11-28T18:38:05.500 回答