GZip / Deflate压缩适用于.NetCore 2.0但不适用于.Net 4.6.2

时间:2018-02-05 14:08:37

标签: c# .net-core gzip deflate .net-4.6.2

我已经编写了一些使用Gzip或Deflate压缩和解压缩数据的代码(都在System.IO.Compression中),我在.NetCore项目中测试了它,它工作正常并且所有测试用例都通过了。所以我在.Net 4.6.2项目中回收了相同的代码,尽管msdn文档说它兼容,但我仍然遇到问题。在这里,你是我讨论的代码部分

public virtual byte[] Encode<TObject>(TObject objectToEncode) where TObject : class, new()
    {

        if (objectToEncode == null) throw new ArgumentNullException(nameof(objectToEncode));

        byte[] jsonResult = null;
        using (var ms = new MemoryStream())
        {

            //Generazione del Json
            using (var textWriter = new StreamWriter(ms, System.Text.Encoding.UTF8))
            {
                using (var jsonWriter = new JsonTextWriter(textWriter))
                {
                    JsonSerializer serializer = new JsonSerializer();
                    serializer.Serialize(jsonWriter, objectToEncode, objectToEncode.GetType());
                    jsonWriter.Flush();
                    textWriter.Flush();
                    ms.Flush();
                    //Compressione Json   
                    jsonResult = ms.ToArray();
                }
            }
        }
        using (var msResult = new MemoryStream())
        {
            using (var encodingStream = GenerateEncodingStream(msResult))
            {
                encodingStream.Write(jsonResult, 0, Convert.ToInt32(jsonResult.Length));
                encodingStream.Flush();
                msResult.Position = 0;
                return msResult.ToArray();
            }
        }
    }

GenerateEncondingStream只需调用DeflateStream或Gzipstream的构造函数,具体取决于您选择的构造函数。

问题: 如果我使用Deflate,msResult.Lenght是0个单元格,而如果我使用GZip长度msResult.Length是同一数据集的10个单元格(.NetCore项目中都是211)。

大量使用Flush()是为了确保每个流都完全刷新到应有的位置。 是否存在.Net 4.6.2的问题或者我的代码错了?谢谢你的帮助!

编辑: 同样的问题,但是解压缩和反序列化:如果我解压缩然后在关闭所有流后反序列化,我的性能比下面列出的使用封装流的版本高出10%。 在解压缩时,下面的代码在反序列化时失败。 我没有想法,因为具有10%效率的版本是不可接受的......

public virtual async Task<object> DecodeAsync(byte[] encodedObject, Type decodedObjectType, CancellationToken cancellationToken)
    {           
        cancellationToken.ThrowIfCancellationRequested();

        if (encodedObject == null) throw new ArgumentNullException(nameof(encodedObject));

        if (encodedObject.Length == 0) throw new ArgumentException(nameof(encodedObject));

        using (var compressedStream = new MemoryStream(encodedObject))
        {
            using (var csStream = GenerateDecodingStream(compressedStream))
            {
                using (var decompressedStream = new MemoryStream())
                {
                    using (StreamReader sr = new StreamReader(decompressedStream, System.Text.Encoding.UTF8))
                    {
                        using (var reader = new JsonTextReader(sr))
                        {
                            JsonSerializer serializer = new JsonSerializer();
                            return serializer.Deserialize(reader, decodedObjectType);

                        }
                    }
                }
            }
        }
    }

1 个答案:

答案 0 :(得分:4)

reference source of DeflateStream中,Flush() 无法执行任何操作

查看反射器,常见的.NET Framework Flush()也是如此。所以基本上,Flush()不想刷新 - 大概是为了最大限度地提高压缩效率。相反,仅在数据大小足够大或处置时才会进行刷新。

相比之下,在.NET Core源代码中,Flush() actually flushes

所以:在您关闭包含.ToArray()的所有内容之后,将您的MemoryStream来电转移到

所以:

using (var ms = new MemoryStream())
{

    //Generazione del Json
    using (var textWriter = new StreamWriter(ms, System.Text.Encoding.UTF8))
    {
        using (var jsonWriter = new JsonTextWriter(textWriter))
        {
            JsonSerializer serializer = new JsonSerializer();
            serializer.Serialize(jsonWriter, objectToEncode, objectToEncode.GetType());                    
        }
    }
    jsonResult = ms.ToArray();
}
using (var msResult = new MemoryStream())
{
    using (var encodingStream = GenerateEncodingStream(msResult))
    {
        encodingStream.Write(jsonResult, 0, Convert.ToInt32(jsonResult.Length));                
    }
    return msResult.ToArray();
}