GZip/Deflate 压缩适用于 .NetCore 2.0 但不适用于 .Net 4.6.2
GZip/Deflate compression works for .NetCore 2.0 but not for .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 Length 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);
}
}
}
}
}
}
在 reference source of DeflateStream
中,Flush()
不做任何事情。
查看反射器,常规 .NET Framework Flush()
也是如此。所以基本上,Flush()
不想刷新 - 大概是为了最大化压缩效果。相反,仅当数据大小足够大或 disposed.
时才会刷新
相比之下,在 .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();
}
我已经编写了一些使用 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 Length 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);
}
}
}
}
}
}
在 reference source of DeflateStream
中,Flush()
不做任何事情。
查看反射器,常规 .NET Framework Flush()
也是如此。所以基本上,Flush()
不想刷新 - 大概是为了最大化压缩效果。相反,仅当数据大小足够大或 disposed.
相比之下,在 .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();
}