DeflateStream doesnt work on MemoryStream?

本文关键字:MemoryStream on work doesnt DeflateStream | 更新日期: 2023-09-27 18:29:37

我有以下代码:

MemoryStream resultStream = new MemoryStream();
string users = ""//Really long string goes here
BinaryFormatter bFormatter = new BinaryFormatter();
using (MemoryStream assignedUsersStream = new MemoryStream())
{
    bFormatter.Serialize(assignedUsersStream, users);
    assignedUsersStream.Position = 0;
    using (var compressionStream =
        new DeflateStream(resultStream, CompressionLevel.Optimal))
    {
        assignedUsersStream.CopyTo(compressionStream);
        Console.WriteLine("Compressed from {0} to {1} bytes.",
            assignedUsersStream.Length.ToString(),
            resultStream.Length.ToString());
    }
}            

问题是resultStream总是空的!

我在这里做错了什么?

DeflateStream doesnt work on MemoryStream?

将验证WriteLine置于using之外。缓冲区尚未刷新。

using (DeflateStream compressionStream = new DeflateStream(resultStream, CompressionLevel.Optimal))
{
    assignedUsersStream.CopyTo(compressionStream);
    //Console.WriteLine("Compressed from {0} to {1} bytes.",
    //       assignedUsersStream.Length.ToString(), resultStream.Length.ToString());
}
Console.WriteLine("Compressed from {0} to {1} bytes.",
     assignedUsersStream.Length, resultStream.ToArray().Length);

除此之外,您不需要在一个写行中使用所有的ToString()

PS:BinaryFormatter对字符串所做的只是写入带有长度前缀的字节。如果你不需要前缀(我猜),它可能会变成:

string users = "";//Really long string goes here
byte[] result;  
using (MemoryStream resultStream = new MemoryStream())
{
    using (DeflateStream compressionStream = new DeflateStream(resultStream,
             CompressionLevel.Optimal))
    {
        byte[] inBuffer = Encoding.UTF8.GetBytes(users);
        compressionStream.Write(inBuffer, 0, inBuffer.Length);
    }
    result = resultStream.ToArray();
}

反过来也很容易,但您需要估计最大长度来创建读取缓冲区:

string users2 = null;
using (MemoryStream resultStream = new MemoryStream(result))
{
    using (DeflateStream compressionStream = new  DeflateStream(resultStream,
            CompressionMode.Decompress))
    {
        byte[] outBuffer = new byte[2048];   // need an estimate here
        int length = compressionStream.Read(outBuffer, 0, outBuffer.Length);
        users2 = Encoding.UTF8.GetString(outBuffer, 0, length);                        
    }                    
}

这是因为DeflateStream在关闭之前不会将数据刷新到底层流。关闭后,resultStream将包含压缩数据。请注意,默认情况下,DeflateStream会在基础流关闭时关闭它,但您不希望这样,因此需要为leaveOpen参数传递true。此外,您不需要2个内存流,只需直接序列化到compressionStream:

    string users = ""; //Really long string goes here
    BinaryFormatter bFormatter = new BinaryFormatter();
    using (MemoryStream resultStream = new MemoryStream())
    {
        using (DeflateStream compressionStream = new DeflateStream(resultStream, CompressionLevel.Optimal, true))
        {
            bFormatter.Serialize(compressionStream, users);
            Console.WriteLine(resultStream.Length); // 0 at this point
        }
        Console.WriteLine(resultStream.Length); // now contains the actual length
    } 

根据原始答案(我没有足够的学分投票否决)

将您的控制WriteLine置于使用之外

这是不完整的,因此IMO具有误导性DeflateStreamDispose(bool)实现Close是底层resultStream,当DeflateStream在被垃圾回收之后是Finalized时。当这种情况发生时,resultStream.Length将抛出:

Unhandled Exception: System.ObjectDisposedException: Cannot access a closed Stream.

换句话说,Thomas Levsque的注释是关键的:还将leaveOpen设置为true

一个有趣的问题,HH和TL提出了一些好的观点。

我来晚了,因为我遇到了同样的问题,并且阅读了相互矛盾的答案。最初的反应是有效的!这个测试也是如此(过于简化以突出答案)

var inStream = new MemoryStream(data);
var outStream = new MemoryStream();
using (var compressor = new DeflateStream(outStream, CompressionLevel.Optimal))
{
    inStream.CopyTo(compressor);
}
return outStream;

其中using块需要完成,触发压缩器的Dispose,后者在内部Flush()es,从而保证outStream包含完整的压缩数据。