DeflateStream не распаковывает данные (первый раз) - PullRequest
8 голосов
/ 11 ноября 2010

Так вот странный. У меня есть этот метод для взятия дефлированной строки в кодировке 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());
            }
        }
    }
}

Возвращает пустую строку , если Я не добавлю второй вызов к 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 / Dispose на ds не имеют эффекта.)

Почему DeflateStream копирует 0 байтов при первом вызове? Я также попытался зациклить с Read(), но он также возвращает ноль при первом вызове, а затем работает на втором.


Обновление: вот метод, который я использую для сжатия данных.
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());
        }
    }
}

1 Ответ

7 голосов
/ 11 ноября 2010

Это происходит, когда сжатые байты являются неполными (т. Е. Не все блоки записаны).

Если я использую ваш Base64Compress со следующим методом Decompress, я получу исключение InvalidDataException с сообщением «Неизвестный тип блока,Поток может быть поврежден. '

Распаковать

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());
  }
}

Обратите внимание, что все работает, как ожидается, при использовании следующего метода сжатия

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();
  }
}

Обновление

Упс, дурацкий ... Вы не можете ToArray поток памяти, пока не утилизируете DeflateStream (так как очистка не реализована (и Deflate / GZip сжимает блоки данных); последний блок записывается только при закрытии/dispose.

Перезаписать сжатие как:

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());
  }
} 
...