如何序列化对象+压缩它然后解压缩+反序列化没有第三方库?

Mar*_*rek 10 c# serialization gzipstream .net-3.5

我在内存中有一个大对象,我想将其作为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();
  }
}
Run Code Online (Sandbox Code Playgroud)

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

我应该使用第三方zip库还是有更好的方法在.NET 3.5中执行此操作.我问题的其他任何替代方案?

编辑:

刚刚在上面的代码中发现了一个错误.安吉洛感谢你的解决.

GZipStream压缩仍然不是很好.与TC 48%压缩相比,gZipStream的平均压缩率为35%.

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

EDIT2:

我发现如何将压缩率从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();
}
Run Code Online (Sandbox Code Playgroud)

Joã*_*elo 13

的代码中存在错误,并且对于评论的解释时间太长,所以即使它没有回答您的真实问题,我也会将其作为答案呈现.

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

固定代码如下:

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();
}
Run Code Online (Sandbox Code Playgroud)

GZipStream在块的基础缓冲区,也写入追加页脚流的结束,这只是在你关闭该流的时刻进行的.

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

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);
}
Run Code Online (Sandbox Code Playgroud)


小智 2

.NET 3.5 中的 GZipStream 不允许您设置压缩级别。这个参数是在.NET 4.5中引入的,但我不知道它是否会给你更好的结果或者升级是否适合你。由于专利的原因,内置算法并不是非常理想。因此,在 3.5 中,获得更好压缩的唯一方法是使用第三方库,例如7zipSharpZipLib提供的SDK。也许您应该尝试使用不同的库来更好地压缩数据