我遇到了这个测试函数的问题,我在其中获取内存字符串,压缩它并解压缩它。压缩效果很好,但我似乎无法使解压缩工作。
//Compress
System.IO.MemoryStream outStream = new System.IO.MemoryStream();
GZipStream tinyStream = new GZipStream(outStream, CompressionMode.Compress);
mStream.Position = 0;
mStream.CopyTo(tinyStream);
//Decompress
outStream.Position = 0;
GZipStream bigStream = new GZipStream(outStream, CompressionMode.Decompress);
System.IO.MemoryStream bigStreamOut = new System.IO.MemoryStream();
bigStream.CopyTo(bigStreamOut);
//Results:
//bigStreamOut.Length == 0
//outStream.Position == the end of the stream.
我相信bigStream out至少应该包含数据,特别是在我的源流(outStream)被读取时。这是一个MSFT错误还是我的?
答案 0 :(得分:95)
您的代码中发生的事情是您不断打开流,但是您永远不会关闭它们。
在第2行中,您创建了GZipStream
。在感觉它是正确的时间之前,此流不会向底层流写入任何内容。你可以通过关闭来告诉它。
但是,如果您关闭它,它也会关闭基础流(outStream
)。因此,您无法在其上使用mStream.Position = 0
。
您应该始终使用using
来确保所有流都关闭。以下是您的代码的变体。
var inputString = "“ ... ”";
byte[] compressed;
string output;
using (var outStream = new MemoryStream())
{
using (var tinyStream = new GZipStream(outStream, CompressionMode.Compress))
using (var mStream = new MemoryStream(Encoding.UTF8.GetBytes(inputString)))
mStream.CopyTo(tinyStream);
compressed = outStream.ToArray();
}
// “compressed” now contains the compressed string.
// Also, all the streams are closed and the above is a self-contained operation.
using (var inStream = new MemoryStream(compressed))
using (var bigStream = new GZipStream(inStream, CompressionMode.Decompress))
using (var bigStreamOut = new MemoryStream())
{
bigStream.CopyTo(bigStreamOut);
output = Encoding.UTF8.GetString(bigStreamOut.ToArray());
}
// “output” now contains the uncompressed string.
Console.WriteLine(output);
答案 1 :(得分:33)
这是一个众所周知的问题:http://blogs.msdn.com/b/bclteam/archive/2006/05/10/592551.aspx
我已经改变了你的代码,所以这个有用:
var mStream = new MemoryStream(new byte[100]);
var outStream = new System.IO.MemoryStream();
using (var tinyStream = new GZipStream(outStream, CompressionMode.Compress))
{
mStream.CopyTo(tinyStream);
}
byte[] bb = outStream.ToArray();
//Decompress
var bigStream = new GZipStream(new MemoryStream(bb), CompressionMode.Decompress);
var bigStreamOut = new System.IO.MemoryStream();
bigStream.CopyTo(bigStreamOut);
答案 2 :(得分:5)
另一种实现,在VB.NET中:
Imports System.Runtime.CompilerServices
Imports System.IO
Imports System.IO.Compression
Public Module Compressor
<Extension()> _
Function CompressASCII(str As String) As Byte()
Dim bytes As Byte() = Encoding.ASCII.GetBytes(str)
Using ms As New MemoryStream
Using gzStream As New GZipStream(ms, CompressionMode.Compress)
gzStream.Write(bytes, 0, bytes.Length)
End Using
Return ms.ToArray
End Using
End Function
<Extension()> _
Function DecompressASCII(compressedString As Byte()) As String
Using ms As New MemoryStream(compressedString)
Using gzStream As New GZipStream(ms, CompressionMode.Decompress)
Using sr As New StreamReader(gzStream, Encoding.ASCII)
Return sr.ReadToEnd
End Using
End Using
End Using
End Function
Sub TestCompression()
Dim input As String = "fh3o047gh"
Dim compressed As Byte() = input.CompressASCII()
Dim decompressed As String = compressed.DecompressASCII()
If input <> decompressed Then
Throw New ApplicationException("failure!")
End If
End Sub
End Module
答案 3 :(得分:2)
对MemoryStream
进行压缩和解压缩的方法是:
public static Stream Compress(
Stream decompressed,
CompressionLevel compressionLevel = CompressionLevel.Fastest)
{
var compressed = new MemoryStream();
using (var zip = new GZipStream(compressed, compressionLevel, true))
{
decompressed.CopyTo(zip);
}
compressed.Seek(0, SeekOrigin.Begin);
return compressed;
}
public static Stream Decompress(Stream compressed)
{
var decompressed = new MemoryStream();
using (var zip = new GZipStream(compressed, CompressionMode.Decompress, true))
{
zip.CopyTo(decompressed);
}
decompressed.Seek(0, SeekOrigin.Begin);
return decompressed;
}
这会使压缩/解压缩的流保持打开状态,并且在创建后可以使用。
答案 4 :(得分:1)
public static byte[] compress(byte[] data)
{
using (MemoryStream outStream = new MemoryStream())
{
using (GZipStream gzipStream = new GZipStream(outStream, CompressionMode.Compress))
using (MemoryStream srcStream = new MemoryStream(data))
srcStream.CopyTo(gzipStream);
return outStream.ToArray();
}
}
public static byte[] decompress(byte[] compressed)
{
using (MemoryStream inStream = new MemoryStream(compressed))
using (GZipStream gzipStream = new GZipStream(inStream, CompressionMode.Decompress))
using (MemoryStream outStream = new MemoryStream())
{
gzipStream.CopyTo(outStream);
return outStream.ToArray();
}
}
答案 5 :(得分:1)
如果您正在尝试使用MemoryStream(例如将其传递给另一个函数)但是接收异常&#34;无法访问已关闭的流。&#34;然后你可以使用另一个GZipStream构造函数来帮助你。
通过传入一个true到leaveOpen参数,你可以指示GZipStream在处理它之后让流保持打开状态,默认情况下它会关闭目标流(我没想到)。 https://msdn.microsoft.com/en-us/library/27ck2z1y(v=vs.110).aspx
using (FileStream fs = File.OpenRead(f))
using (var compressed = new MemoryStream())
{
//Instruct GZipStream to leave the stream open after performing the compression.
using (var gzipstream = new GZipStream(compressed, CompressionLevel.Optimal, true))
fs.CopyTo(gzipstream);
//Do something with the memorystream
compressed.Seek(0, SeekOrigin.Begin);
MyFunction(compressed);
}
答案 6 :(得分:0)
如果仍然需要,则可以使用GZipStream构造函数和boolean参数(有两个此类构造函数)并在其中传递true值:
tinyStream = new GZipStream(outStream, CompressionMode.Compress, true);
在这种情况下,当您关闭tynyStream时,输出流仍将打开。不要忘记复制数据:
mStream.CopyTo(tinyStream);
tinyStream.Close();
现在您有了带有压缩数据的内存流 outStream
对U的错误和亲吻
祝你好运
答案 7 :(得分:0)
请参考以下链接,避免使用双重MemoryStream 。 https://stackoverflow.com/a/53644256/1979406
答案 8 :(得分:0)
我遇到一个问题,其中*.CopyTo(stream)*
最终会得到byte[0]
结果。
解决方法是在调用.Position=0
之前添加.CopyTo(stream)
PropertyDescriptor.ResetValue
我还使用了BinaryFormatter
,如果在反序列化之前位置未设置为0,则会抛出“ 解析完成之前遇到的流结束”异常。
Answered here
这是对我有用的代码。
public static byte[] SerializeAndCompressStateInformation(this IPluginWithStateInfo plugin, Dictionary<string, object> stateInfo)
{
byte[] retArr = new byte[] { byte.MinValue };
try
{
using (MemoryStream msCompressed = new MemoryStream())//what gzip writes to
{
using (GZipStream gZipStream = new GZipStream(msCompressed, CompressionMode.Compress))//setting up gzip
using (MemoryStream msToCompress = new MemoryStream())//what the settings will serialize to
{
BinaryFormatter formatter = new BinaryFormatter();
//serialize the info into bytes
formatter.Serialize(msToCompress, stateInfo);
//reset to 0 to read from beginning byte[0] fix.
msToCompress.Position = 0;
//this then does the compression
msToCompress.CopyTo(gZipStream);
}
//the compressed data as an array of bytes
retArr = msCompressed.ToArray();
}
}
catch (Exception ex)
{
Logger.Error(ex.Message, ex);
throw ex;
}
return retArr;
}
public static Dictionary<string, object> DeserializeAndDecompressStateInformation(this IPluginWithStateInfo plugin, byte[] stateInfo)
{
Dictionary<string, object> settings = new Dictionary<string, object>();
try
{
using (MemoryStream msDecompressed = new MemoryStream()) //the stream that will hold the decompressed data
{
using (MemoryStream msCompressed = new MemoryStream(stateInfo))//the compressed data
using (GZipStream gzDecomp = new GZipStream(msCompressed, CompressionMode.Decompress))//the gzip that will decompress
{
msCompressed.Position = 0;//fix for byte[0]
gzDecomp.CopyTo(msDecompressed);//decompress the data
}
BinaryFormatter formatter = new BinaryFormatter();
//prevents 'End of stream encountered' error
msDecompressed.Position = 0;
//change the decompressed data to the object
settings = formatter.Deserialize(msDecompressed) as Dictionary<string, object>;
}
}
catch (Exception ex)
{
Logger.Error(ex.Message, ex);
throw ex;
}
return settings;
}