2012-02-24 1 views
1

Итак, я пытаюсь сжать массив байтов (через Stream). ExtendedStream - это просто класс, который я сделал с интерфейсом с базовым потоком (по умолчанию MemoryStream). Если я беру свои исходные данные, сжимаю их, распаковываю, а затем сравниваю размер распакованных данных с размером исходных данных (до сжатия), оказывается, что он меньше оригинала.Исходный файл больше, чем файл GZip для распаковки

Оригинал Длина: 51695, Сжатый длина: 26014, расжатая длина: 48685.

Я хранящие плитки (7 байт). Сжатие с использованием классов GZip, предоставляемых в пространстве имен System.IO.Compression.

public static ExtendedStream GZipDecompress(ExtendedStream stream) 
    { 
     ExtendedStream outStream = new ExtendedStream(); 
     GZipStream decompressStream = new GZipStream(stream.BaseStream, CompressionMode.Decompress, true); 
     int b = -1; 

     while ((b = decompressStream.ReadByte()) != -1) 
     { 
      outStream.WriteByte((Byte)b); 
     } 

     outStream.Seek(0, SeekOrigin.Begin); 
     return outStream; 
    } 

    public static ExtendedStream GZipCompress(ExtendedStream stream) 
    { 
     ExtendedStream outStream = new ExtendedStream(); // base stream is a memorystream 
     GZipStream compressStream = new GZipStream(outStream.BaseStream, CompressionMode.Compress, true); 
     compressStream.Write(stream.ToArray(), 0, (int)stream.Length); 
     compressStream.Flush(); 
     outStream.Seek(0, SeekOrigin.Begin); 
     return outStream; 
    } 

Надеюсь, этого достаточно информации.

+1

Во-первых, вы должны звонить. Поместите объекты GZipStream, когда вы закончите. Также при записи вам нужно позвонить .Flush на outStream после того, как вы избавитесь от своего GZipStream. В-третьих, если это .NET4, используйте метод .CopyTo для основного элемента вашего входного потока, чтобы скопировать данные из ввода в выходной файл (вместо использования .ToArray, который не будет масштабироваться по мере увеличения ваших потоков). – Joe

+0

Нет, вам не нужно вызывать flush на «outStream» при распаковке или сжатии. Данные уже находятся в потоке. Flushing ничего не сделал бы, так как это MemoryStream (и FYI MemoryStream переопределяет Flush, чтобы он ничего не делал). Я сохраню метод CopyTo, но GC просто исправит все для меня (небрежный дизайн, который я знаю, но это не цель дизайна № 1). –

+1

@ Супа, нет; Джо прав. Вы ** должны должны ** формально закрыть/удалить потоки сжатия. Флеш не может быть пустым, если он не знает, что больше ничего не происходит, что происходит только при закрытии. Ограничение сжатия. Это абсолютно критично в сжатии (как вы думаете, я еще подчеркивал это достаточно?). Btw: копирование отдельных байтов - это ужасный способ сделать это. –

ответ

1

Вы must закрыть поток сжатия; он не может записать все данные, пока вы не сделаете, из-за блокировки вопросов:

public static ExtendedStream GZipCompress(ExtendedStream stream) 
{ 
    ExtendedStream outStream = new ExtendedStream(); 
    using(var compressStream = new GZipStream(outStream.BaseStream, CompressionMode.Compress, false)) { 
     compressStream.Write(stream.GetBuffer(), 0, (int)stream.Length); 
    } 
    outStream.Seek(0, SeekOrigin.Begin); 
    return outStream; 
} 

Примечание: как правило, я бы использовать CopyTo (или ручной зацикливания), чтобы сделать запись, но так как это память на основе GetBuffer() дешевле.

Ваш декомпрессия может быть просто:

decompressStream.WriteTo(outStream); 

Повсеместно обеих частей этого, самая большая проблема (что укусил вас здесь) не утилизации ваши одноразовые предметы. Вы должны сделать это; это требование API. Чтобы избежать преждевременного удаления внешнего потока, передайте «false» в конструктор GZipStream. Например:

using(var decompressStream = new GZipStream(stream.BaseStream, CompressionMode.Decompress, false)) { 
    decompressionStream.CopyTo(outStream); 
} 
+0

Проблема, по-видимому, заключалась в том, чтобы не смывать/закрывать фактические потоки сжатия/декомпрессии, как вы сказали. Спасибо за предложение GetBuffer. Я ценю, что вы не разговариваете со мной и фактически объясняете, в чем проблема. –

+0

@Supah да, это необходимая особенность таких вещей, как сжатие и шифрование, которые они накапливают блок данных, а затем записывают целый блок за раз. Это означает, что обычно существуют остаточные данные, ожидающие записи, что даже «Flush()» не может сдвигаться. –