如何使用gzip压缩.net对象实例

5

我希望在将数据库查询结果添加到缓存之前对其进行压缩。

我想要能够压缩任何引用类型。

我已经有了一个可以压缩字符串的工作版本。这个想法基于Scott Hanselman的博客文章http://shrinkster.com/173t

有没有关于压缩.NET对象的任何想法?

我知道它将是只读缓存,因为缓存中的对象将只是字节数组。

4个回答

21

这对于任何引用类型都不起作用。这将适用于Serializable类型。连接一个BinaryFormatter到一个压缩流,该流被管道连接到一个文件:

var formatter = new BinaryFormatter();
using (var outputFile = new FileStream("OutputFile", FileMode.CreateNew))
using (var compressionStream = new GZipStream(
                         outputFile, CompressionMode.Compress)) {
   formatter.Serialize(compressionStream, objToSerialize);
   compressionStream.Flush();
}

你可以使用MemoryStream将内容保存在内存中,而不是写入文件。然而我怀疑这并不是缓存的有效解决方案。


1
谢谢,这真的很有帮助。解压缩会是什么样子呢?我以前从未使用过BinaryFormatter。 - Matt Peters
感谢您使这段代码易于复制和粘贴。我经常需要格式化代码,现在这只是一个我可以在Google上轻松找到的片段。+1 - Bryan Boettcher

3

今天我为我的应用程序添加了GZipStream支持,所以我可以在这里分享一些代码;

序列化:

using (Stream s = File.Create(PathName))
{
    RijndaelManaged rm = new RijndaelManaged();
    rm.Key = CryptoKey;
    rm.IV = CryptoIV;
    using (CryptoStream cs = new CryptoStream(s, rm.CreateEncryptor(), CryptoStreamMode.Write))
    {
        using (GZipStream gs = new GZipStream(cs, CompressionMode.Compress))
        {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(gs, _instance);
        }
    }
}

反序列化:

using (Stream s = File.OpenRead(PathName))
{
    RijndaelManaged rm = new RijndaelManaged();
    rm.Key = CryptoKey;
    rm.IV = CryptoIV;
    using (CryptoStream cs = new CryptoStream(s, rm.CreateDecryptor(), CryptoStreamMode.Read))
    {
        using (GZipStream gs = new GZipStream(cs, CompressionMode.Decompress))
        {
            BinaryFormatter bf = new BinaryFormatter();
            _instance = (Storage)bf.Deserialize(gs);
        }
    }
}

注意:如果你使用CryptoStream,非常重要的一点是正确地链接(解)压缩和(解)加密,因为你希望在加密从数据中创建噪声之前消除熵。


3
您将什么样的对象放入缓存中?它们是类型化的对象吗?还是像DataTable这样的东西?对于DataTable,您可以通过GZipStream压缩为xml进行存储。对于类型化(实体)对象,您可能需要对它们进行序列化。
您可以使用BinaryFormatterGZipStream,也可以使用一些已经非常紧凑的序列化工具,例如protobuf-net(免费)。特别是,像protobuf-net这样的工具的优点是,您可以在反序列化期间不必支付解压缩的CPU成本就能获得减小的数据大小。在添加GZipStream之前,在某些测试中,它比BinaryFormatter快4倍。将额外的时间加到BinaryFormatter上以进行GZip操作,它应该会以相当大的优势获胜。

1

以下是如何完成此操作的方法。

GzipStream:提供用于压缩和解压缩流的方法和属性。

使用binaryformatter将对象序列化到内存流中,并将该内存流连接到Gzipstream中。

压缩的代码如下:

            public static byte[] ObjectToCompressedByteArray(object obj)
                    {
                        try
                        {
                            using (var memoryStream = new System.IO.MemoryStream())
                            {
                                using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress))
                                {
                                    var binaryFormatter = new BinaryFormatter();
                                    binaryFormatter.Serialize(gZipStream, obj);
                                }
                                return memoryStream.ToArray();
                            }
                        }
                        catch (Exception ex)
                        {
                            LoggerWrapper.CMLogger.LogMessage(
                                $"EXCEPTION: BSExportImportHelper.ObjectToByteArray - : {ex.Message}", LoggerWrapper.CMLogger.CMLogLevel.Error);
                            throw;
                        }

                    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接