c# - 如何在没有第三方库的情况下序列化对象+压缩然后解压+反序列化?

标签 c# serialization .net-3.5 gzipstream

我在内存中有一个大对象,我想将其作为 blob 保存到数据库中。 我想在保存之前压缩它,因为数据库服务器通常不在本地。

这是我目前拥有的:

using (var memoryStream = new MemoryStream())
{
  using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress))
  {
    BinaryFormatter binaryFormatter = new BinaryFormatter();
    binaryFormatter.Serialize(gZipStream, obj);

    return memoryStream.ToArray();
  }
}

然而,当我使用 Total Commander 压缩相同的字节时,它总是至少将大小减少 50%。使用上面的代码,它将 58MB 压缩到 48MB,任何小于 15MB 的东西都会变得更大。

我应该使用第三方 zip 库还是在 .NET 3.5 中有更好的方法? 我的问题还有其他替代方案吗?

编辑:

刚刚在上面的代码中发现了一个错误。 Angelo 感谢您的修复。

GZipStream 压缩仍然不是很好。 与 TC 48% 的压缩率相比,我通过 gZipStream 获得了平均 35% 的压缩率。

我不知道我从以前的版本中得到了什么样的字节:)

编辑 2:

我发现了如何将压缩率从 20% 提高到 47%。 我不得不使用两个内存流而不是一个!谁能解释为什么会这样?

这是一个带有 2 个内存流的代码,压缩效果更好!!!

using (MemoryStream msCompressed = new MemoryStream())
using (GZipStream gZipStream = new GZipStream(msCompressed, CompressionMode.Compress))
using (MemoryStream msDecompressed = new MemoryStream())
{
  new BinaryFormatter().Serialize(msDecompressed, obj);
  byte[] byteArray = msDecompressed.ToArray();

  gZipStream.Write(byteArray, 0, byteArray.Length);
  gZipStream.Close();
  return msCompressed.ToArray();
}

最佳答案

在您的代码中有一个错误,并且解释太长而无法发表评论,所以我将其作为答案提供,即使它没有回答您的真正问题。

您需要仅在关闭GZipStream 后调用memoryStream.ToArray(),否则您将创建无法压缩的数据反序列化。

固定代码如下:

using (var memoryStream = new System.IO.MemoryStream())
{
  using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress))
  {
    BinaryFormatter binaryFormatter = new BinaryFormatter();
    binaryFormatter.Serialize(gZipStream, obj);
  }
  return memoryStream.ToArray();
}

GZipStream 以 block 的形式写入底层缓冲区,并将页脚附加到流的末尾,这仅在您关闭流时执行。

您可以通过运行以下代码示例轻松证明这一点:

byte[] compressed;
int[] integers = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

var mem1 = new MemoryStream();
using (var compressor = new GZipStream(mem1, CompressionMode.Compress))
{
    new BinaryFormatter().Serialize(compressor, integers);
    compressed = mem1.ToArray();
}

var mem2 = new MemoryStream(compressed);
using (var decompressor = new GZipStream(mem2, CompressionMode.Decompress))
{
    // The next line will throw SerializationException
    integers = (int[])new BinaryFormatter().Deserialize(decompressor);
}

关于c# - 如何在没有第三方库的情况下序列化对象+压缩然后解压+反序列化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12088623/

相关文章:

c# - LINQ 左 JOIN 错误

linq-to-sql - 尽管变更集中有数据,为什么Linq to sql可能无法提交更改以使更新失败

c# - 通过 XAML 将数据库上下文传递给用户控件的 VM

c# - protobuf-net 中的 prepareserializer 有什么作用?

json - 使用 ScalaJson 序列化解决类型不匹配问题

c# - 无法以编程方式反序列化 SOAP 消息

c# - 在 ASP.NET MVC 中无需等待即可启动异步任务的两种方法之间的区别

c# - 从窗口获取线程ID

c# - UWP Application Insights 没有崩溃的调用堆栈

scala - Flink 无法序列化 Scala 类/任务不可序列化