【问题标题】:MemoryStream CopyTo only partially writingMemoryStream CopyTo 仅部分写入
【发布时间】:2013-04-16 23:46:08
【问题描述】:

我快要疯了。在过去的一个小时里,我一直试图让 GzipStream 压缩一个字符串,但无论出于何种原因,它都拒绝将整个字节数组写入内存流。起初我认为它与 using 语句有关,但即使在删除它们之后,它似乎也没有什么不同。

初始配置:

var str = "Here is a relatively simple string to compress";
byte[] compressedBytes;
string returnedData;

var bytes = Encoding.UTF8.GetBytes(str);

工作正常(写入 64 长度字节数组):

using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream()) {
   using (var gs = new GZipStream(mso, CompressionMode.Compress)) {
       msi.CopyTo(gs);
   }

   compressedBytes = mso.ToArray();
}

失败(写入 10 字节长度的数组):

using(var mso = new MemoryStream())
using(var msi = new MemoryStream(bytes))
using(var zip = new GZipStream(mso, CompressionMode.Compress))
{
    msi.CopyTo(zip);
    compressedBytes = mso.ToArray();
}

同样失败(写入 10 字节长度的数组):

var mso = new MemoryStream();
var msi = new MemoryStream(bytes);
var zip = new GZipStream(mso, CompressionMode.Compress);

msi.CopyTo(zip);
compressedBytes = mso.ToArray();

有人可以解释为什么第一个有效,但在另外两个中我得到这些不完整的数组吗?有什么东西从我下面被处理掉了吗?就此而言,有没有办法让我避免使用两个内存流?

谢谢, 放大镜

【问题讨论】:

  • 使用 StreamWriter 而不是 MemoryStream + Encoding.GetBytes。

标签: c# compression gzip memorystream


【解决方案1】:

System.IO.Compression.GZipStream 必须先关闭(处置)才能使用底层流,因为

  1. 面向块工作
  2. 它必须写页脚,包括校验和(见the file format description on Wikipedia

【讨论】:

  • 这对我来说很有意义,因为 GZipStream 无法真正知道我何时完成它,除非我明确处置/关闭它。否则,也许我会对 Zip 流进行一些额外的写入。谢谢!
【解决方案2】:

您正试图在GZipStream 关闭之前获取压缩数据。如您所见,这不会返回完整数据。第一个工作的原因是因为你在调用compressedBytes = mso.ToArray(); GZipStream 已被处理。因此,未经测试,但理论上,您应该能够像这样稍微修改您的第二个代码以使其正常工作。

using(var mso = new MemoryStream())
{
   using(var msi = new MemoryStream(bytes))
   using(var zip = new GZipStream(mso, CompressionMode.Compress))
   {
       msi.CopyTo(zip);
   }
   compressedBytes = mso.ToArray();
}

【讨论】:

    【解决方案3】:

    正如其他人所说,您需要关闭GZipStream才能获得完整数据。 using 语句将导致在块末尾的流上调用 Dispose 方法,如果流尚未关闭,它将关闭流。如果您将zip.Close(); 放在msi.CopyTo(zip); 之后,则上述所有示例都将按预期工作。

    如果你这样写,你可以消除其中一个 MemoryStream:

    using (MemoryStream mso = new MemoryStream())
    {
        using (GZipStream zip = new GZipStream(mso, CompressionMode.Compress))
        {
            zip.Write(bytes, 0, bytes.Length);
        }
        compressedBytes = mso.ToArray();
    }
    

    【讨论】:

    • 感谢 Brian 提供有关如何删除 MemoryStreams 之一的额外提示。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-01
    相关资源
    最近更新 更多