11

我有以下代码:

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总是空的!

我在这里做错了什么?

4

4 回答 4

13

将您的验证 WriteLine 放在使用之外。缓冲区尚未刷新。

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()中的所有这些 s。

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);                        
    }                    
}
于 2013-08-30T19:30:44.967 回答
11

这是因为在DeflateStream关闭之前不会将数据刷新到底层流。关闭后,resultStream将包含压缩数据。请注意,默认情况下,DeflateStream关闭底层流时会关闭它,但您不希望这样,因此您需要传递true参数leaveOpen。此外,您不需要 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
    } 
于 2013-08-30T19:39:17.437 回答
3

从原始答案(我没有足够的学分投反对票)

将您的控件 WriteLine 放在使用之外

这是不完整且具有误导性的。一旦 DeflateStream 超出范围,DeflateStream 就会关闭底层的 resultStream。因此 resultStream.Length 抛出

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

Thomas Levesque 是正确的 => 也设置leaveOpen为 true。

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

于 2015-02-10T11:55:39.030 回答
0

当我遇到同样的问题并阅读相互矛盾的答案时,我来晚了。最初的反应有效!就像这个测试一样(过度简化以突出答案)

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

压缩器需要超出范围,以便 OutStream 可以获取压缩数据。

于 2021-11-24T11:58:53.807 回答