2012-06-25 3 views
0

Я использую GZipStream, чтобы сжать строку, и я изменил два разных примера, чтобы увидеть, что работает. Первый фрагмент кода, который является сильно измененной версией the example in the documentation, просто возвращает пустую строку.Почему один метод строкового сжатия возвращает пустую строку, а другой - нет?

public static String CompressStringGzip(String uncompressed) 
{ 
    String compressedString; 
    // Convert the uncompressed source string to a stream stored in memory 
    // and create the MemoryStream that will hold the compressed string 
    using (MemoryStream inStream = new MemoryStream(Encoding.Unicode.GetBytes(uncompressed)), 
         outStream = new MemoryStream()) 
    { 
     using (GZipStream compress = new GZipStream(outStream, CompressionMode.Compress)) 
     { 
      inStream.CopyTo(compress); 
      StreamReader reader = new StreamReader(outStream); 
      compressedString = reader.ReadToEnd(); 
     } 
    } 
    return compressedString; 

и когда я его отладки, все, что я могу сказать, ничего не читается из reader, который compressedString пуст. Однако второй способ, который я написал, был изменен с CodeProject snippet.

public static String CompressStringGzip3(String uncompressed) 
{ 
    //Transform string to byte array 
    String compressedString; 
    byte[] uncompressedByteArray = Encoding.Unicode.GetBytes(uncompressed); 

    using (MemoryStream outStream = new MemoryStream()) 
    { 
     using (GZipStream compress = new GZipStream(outStream, CompressionMode.Compress)) 
     { 
      compress.Write(uncompressedByteArray, 0, uncompressedByteArray.Length); 
      compress.Close(); 
     } 
     byte[] compressedByteArray = outStream.ToArray(); 
     StringBuilder compressedStringBuilder = new StringBuilder(compressedByteArray.Length); 
     foreach (byte b in compressedByteArray) 
      compressedStringBuilder.Append((char)b); 
     compressedString = compressedStringBuilder.ToString(); 
    } 
    return compressedString; 
} 

Почему первый фрагмент кода не увенчался успехом, пока другой? Хотя они немного разные, я не знаю, почему незначительные изменения во втором фрагменте позволяют ему работать. Строка образца я использую SELECT * FROM foods f WHERE f.name = 'chicken';

+0

Что-нибудь связанное с положением потока? Вы пробовали искать начало потока в методе 1 перед его чтением? – Charleh

+0

Я добавил 'inStream.Seek (0L, SeekOrigin.Begin);' перед строкой: 'inStream.CopyTo (compress);', но метод по-прежнему возвращает пустую строку. –

ответ

1

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

public static String Compress(String decompressed) 
{ 
    byte[] data = Encoding.UTF8.GetBytes(decompressed); 
    using (var input = new MemoryStream(data)) 
    using (var output = new MemoryStream()) 
    { 
     using (var gzip = new GZipStream(output, CompressionMode.Compress, true)) 
     { 
      input.CopyTo(gzip); 
     } 
     return Convert.ToBase64String(output.ToArray()); 
    } 
} 

public static String Decompress(String compressed) 
{ 
    byte[] data = Convert.FromBase64String(compressed); 
    using (MemoryStream input = new MemoryStream(data)) 
    using (GZipStream gzip = new GZipStream(input, CompressionMode.Decompress)) 
    using (MemoryStream output = new MemoryStream()) 
    { 
     gzip.CopyTo(output); 
     StringBuilder sb = new StringBuilder(); 
     return Encoding.UTF8.GetString(output.ToArray()); 

    } 
} 

Объяснение часть проблемы исходит от this question. Хотя я исправил проблему путем изменения кода на то, что я включил в этот ответ, эти строки (в моем исходном коде):

foreach (byte b in compressedByteArray) 
      compressedStringBuilder.Append((char)b); 

проблематичны, потому что, как dlev метко выразился:

You are interpreting each byte as its own character, when in fact that is not the case. Instead, you need the line:

string decoded = Encoding.Unicode.GetString(compressedByteArray); 

The basic problem is that you are converting to a byte array based on an encoding, but then ignoring that encoding when you retrieve the bytes.

Таким образом, проблема решена, и новый код, который я использую, намного более краткий, чем мой исходный код.

0

Вам нужно переместить код ниже снаружи второго используя высказывание:

using (GZipStream compress = new GZipStream(outStream, CompressionMode.Compress)) 
{ 
    inStream.CopyTo(compress); 
    outStream.Position = 0; 
    StreamReader reader = new StreamReader(outStream); 
    compressedString = reader.ReadToEnd(); 
} 

CopyTo() не промывка результатов основного MemoryStream.

Обновление

Кажется, что GZipStream закрывает и распоряжается это основной поток, когда он расположен (не так, как я бы разработан класс). Я обновил образец выше и протестировал его.

+0

За пределами второго (внутреннего?) Выражения 'using'? Я получаю сообщение о том, что 'outStream' был нечитаемым, если я переведу код, о котором идет речь. –

+0

Как просто промывать поток вручную с помощью stream.Flush()? – Charleh

+0

@Charleh также работает, но я думаю, что это более читаемо, чтобы делать это за пределами оператора using, поскольку он четко разделяет две задачи. – Slugart

Смежные вопросы