【问题标题】:DeflateStream doesnt work on MemoryStream?DeflateStream 在 MemoryStream 上不起作用?
【发布时间】:2013-09-03 14:37:25
【问题描述】:

我有以下代码:

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

我在这里做错了什么?

【问题讨论】:

    标签: c# serialization memorystream deflate binary-serialization


    【解决方案1】:

    将您的验证 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);                        
        }                    
    }
    

    【讨论】:

    • 好。请务必阅读 Thomas 关于消除 1 MemoryStream 的答案,您还可以将 Formatter 替换为 Encoding.GetBytes()
    【解决方案2】:

    这是因为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
        } 
    

    【讨论】:

    • 流不必保持打开状态,ToArray() 可以在关闭的 MemoryStream 上正常工作。但同意直接序列化。
    • @HenkHolterman,你是对的;访问流的长度时出现异常,但 ToArray 工作正常。
    【解决方案3】:

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

    将您的控件 WriteLine 放在 using 之外

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

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

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

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

    【讨论】:

    • 我之前没有看到这个,但是在处理它之后访问流是完全可以的,只要它是一个 MemoryStream 。这在我的第一个 sn-p 中并不清楚,但它在第二个,更长的一个和问题中。
    【解决方案4】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-20
      • 1970-01-01
      相关资源
      最近更新 更多