8

だからここに奇妙なものがあります。Base64でエンコードされた収縮した文字列を取得して、元のデータを返すこのメソッドがあります。

public static string Base64Decompress(string base64data)
{
    byte[] b = Convert.FromBase64String(base64data);
    using (var orig = new MemoryStream(b))
    {
        using (var inflate = new MemoryStream())
        {
            using (var ds = new DeflateStream(orig, CompressionMode.Decompress))
            {
                ds.CopyTo(inflate);
                return Encoding.ASCII.GetString(inflate.ToArray());
            }
        }
    }
}

に2番目の呼び出しを追加しない限り、これは空の文字列を返しますds.CopyTo(inflate)。(WTF?)

   ...
            using (var ds = new DeflateStream(orig, CompressionMode.Decompress))
            {
                ds.CopyTo(inflate);
                ds.CopyTo(inflate);
                return Encoding.ASCII.GetString(inflate.ToArray());
            }
   ...

Flush/ Close/ Disposeondsは効果がありません。)

DeflateStream最初の呼び出しで0バイトをコピーするのはなぜですか?でループを試しましRead()たが、最初の呼び出しでゼロを返し、2番目の呼び出しで機能します。


更新:これが私がデータを圧縮するために使用している方法です。

public static string Base64Compress(string data, Encoding enc)
{
    using (var ms = new MemoryStream())
    {
        using (var ds = new DeflateStream(ms, CompressionMode.Compress))
        {
            byte[] b = enc.GetBytes(data);
            ds.Write(b, 0, b.Length);
            ds.Flush();
            return Convert.ToBase64String(ms.ToArray());
        }
    }
}
4

1 に答える 1

7

これは、圧縮されたバイトが不完全な場合 (つまり、すべてのブロックが書き出されていない場合) に発生します。

次の Decompress メソッドで Base64Compress を使用すると、「不明なブロック タイプです。ストリームが破損している可能性があります。

解凍する

public static string Decompress(Byte[] bytes)
{
  using (var uncompressed = new MemoryStream())
  using (var compressed = new MemoryStream(bytes))
  using (var ds = new DeflateStream(compressed, CompressionMode.Decompress))
  {
    ds.CopyTo(uncompressed);
    return Encoding.ASCII.GetString(uncompressed.ToArray());
  }
}

次の Compress メソッドを使用すると、すべてが期待どおりに機能することに注意してください

public Byte[] Compress(Byte[] bytes)
{
  using (var memoryStream = new MemoryStream())
  {
    using (var deflateStream = new DeflateStream(memoryStream, CompressionMode.Compress))
      deflateStream.Write(bytes, 0, bytes.Length);

    return memoryStream.ToArray();
  }
}

アップデート

おっと、愚かな私... DeflateStream を破棄するまでメモリ ストリームを ToArray することはできません (フラッシュは実際には実装されていないため (および Deflate/GZip はデータ ブロックを圧縮するため)、最後のブロックはクローズ/破棄時にのみ書き込まれます。

圧縮を次のように書き直します。

public static string Base64Compress(string data, Encoding enc)
{
  using (var ms = new MemoryStream())
  {
    using (var ds = new DeflateStream(ms, CompressionMode.Compress))
    {
      byte[] b = enc.GetBytes(data);
      ds.Write(b, 0, b.Length);
    }

    return Convert.ToBase64String(ms.ToArray());
  }
} 
于 2010-11-11T20:56:45.393 に答える