Сжатие данных GZipStream
От: SeLo  
Дата: 06.04.08 09:58
Оценка:
Сжатие данных не работает так как хотелось бы:

Пример позаимсвовал из одной книги:

string inFileName = @"c:\test.txt";
string outFileName = @"c:\test_Compres.txt";

FileStream sourceFile = File.OpenRead(inFileName);
FileStream destFile = File.Create(outFileName);

GZipStream compStream = new GZipStream(destFile, CompressionMode.Compress);

//Из книги
//int theByte = sourceFile.ReadByte();
//while (theByte != -1)
//{
//    compStream.WriteByte((byte)theByte);
//    theByte = sourceFile.ReadByte();
//} // 559 -> 528

// Мой вариант (тестовый, плз. без критики)
byte[] byteArray = new byte[sourceFile.Length];
sourceFile.Read(byteArray, 0, (int)sourceFile.Length);
compStream.Write(byteArray, 0, byteArray.Length);
// 559 -> 13

compStream.Close();


Оказалось, что если, как описанно в книге сбрасывать, по одному байту, по всей видимости сразу же компрессирует этот байт. В результате никакой компрессии 559 Кб -> 528 Kб. Я ожидал, что GZipStream накапилвает эти байты в каком-то буфере и потом после заполнения этого буфера, компресирует данные и затем передает их в FileStream. Если в GZipStream передавать куски байтов, то компрессия на порядок лучше . Вопрос: можно ли как-то контроллировать буфер (размер, время сброса данных — типа AutoFlush = False и т.д) или для нормальной компрессии возможна только запись сегметами (например по 100 байт)?
Re: Сжатие данных GZipStream
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 06.04.08 10:12
Оценка:
Здравствуйте, SeLo, Вы писали:

SL>// Мой вариант (тестовый, плз. без критики)

SL>byte[] byteArray = new byte[sourceFile.Length];
SL>sourceFile.Read(byteArray, 0, (int)sourceFile.Length);
SL>compStream.Write(byteArray, 0, byteArray.Length);
SL>// 559 -> 13

Без критики не получится. Кто исходный поток в начало перематывать будет?
... <<RSDN@Home 1.2.0 alpha 4 rev. 1074 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re: Сжатие данных GZipStream
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.04.08 10:19
Оценка:
Здравствуйте, SeLo, Вы писали:

SL>Оказалось, что если, как описанно в книге сбрасывать, по одному байту, по всей видимости сразу же компрессирует этот байт.

У тебя в коде где-то ошибка. Никакой разницы, блоками какого размера оперировать, нет.

Попробуй сначала написать программу, которая работает. А потом уже тренироваться в коэффициентах сжатия.
Как минимум, все потоки нужно закрывать:
int blockSize = 1; // вот этим будешь играть, меняя размер блока
string inFileName = @"c:\test.txt";
string outFileName = @"c:\test_Compres.txt";
byte[] buffer = new byte[blockSize];

using(FileStream sourceFile = File.OpenRead(inFileName))
using(FileStream destFile = File.Create(outFileName)))
using(GZipStream compStream = new GZipStream(destFile, CompressionMode.Compress))
{
  int actualSize;
    while ((actualSize = sourceFile.Read(buffer, 0, blockSize)>0)
        compStream.Write(buffer, 0, actualSize);
}
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Сжатие данных GZipStream
От: Аноним  
Дата: 06.04.08 10:20
Оценка:
Здравствуйте, SeLo, Вы писали:

SL>поскипано

SL>Я ожидал, что GZipStream накапилвает эти байты в каком-то буфере и .....
SL>поскипано
Обычно чтобы не предугадывать как и что будет работать — читают MSDN, в крайнем случае берут рефлектор и смотрят напрямую.
Re[2]: Сжатие данных GZipStream
От: SeLo  
Дата: 06.04.08 10:28
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, SeLo, Вы писали:


SL>>// Мой вариант (тестовый, плз. без критики)

SL>>byte[] byteArray = new byte[sourceFile.Length];
SL>>sourceFile.Read(byteArray, 0, (int)sourceFile.Length);
SL>>compStream.Write(byteArray, 0, byteArray.Length);
SL>>// 559 -> 13

AVK>Без критики не получится. Кто исходный поток в начало перематывать будет?


Неужели Length исходного потока смещает указатель? Я пробовал мой архив распаковывать > восстонавливает 100%
Re[3]: Сжатие данных GZipStream
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 06.04.08 10:30
Оценка:
Здравствуйте, SeLo, Вы писали:

SL>Неужели Length исходного потока смещает указатель?


Указатель смещает предыдущее чтение.
... <<RSDN@Home 1.2.0 alpha 4 rev. 1074 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[2]: Сжатие данных GZipStream
От: SeLo  
Дата: 06.04.08 10:32
Оценка: 84 (1)
S>У тебя в коде где-то ошибка. Никакой разницы, блоками какого размера оперировать, нет.
Пример проверил: в точности как в книге, ошибок нет


S>int blockSize = 1; // вот этим будешь играть, меняя размер блока

Получается размер буфера все-таки влияет на коэффициент сжатия. Именно это мне и было интересно
Re[4]: Сжатие данных GZipStream
От: SeLo  
Дата: 06.04.08 10:35
Оценка:
AVK>Указатель смещает предыдущее чтение.

Все равно не пойму, как это может повлиять на результаты
Re[2]: Сжатие данных GZipStream
От: SeLo  
Дата: 06.04.08 10:43
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, SeLo, Вы писали:


SL>>поскипано

SL>>Я ожидал, что GZipStream накапилвает эти байты в каком-то буфере и .....
SL>>поскипано
А>Обычно чтобы не предугадывать как и что будет работать — читают MSDN, в крайнем случае берут рефлектор и смотрят напрямую.

Вот в MSDN говориться что WriteByte по сути вызывает метод Write, который (извиняюсь немецкий мне роднее):

Der verwendete Puffer ist ein interner Puffer. Der Schreibvorgang wird möglicherweise nicht unmittelbar ausgeführt, wird jedoch gepuffert, bis die Puffergröße erreicht ist oder bis die Flush-Methode oder die Close-Methode aufgerufen wird.

ЗДесь говориться, что есть внутренний буфер. Запись не будет непосредственно выполненна, а проверенно заполненн ли буфер. Также можно выписать данные методо Flush и Close.

Но какой размер буфера? и как на этот размер влиять?
Re[3]: Сжатие данных GZipStream
От: Аноним  
Дата: 06.04.08 10:49
Оценка:
Здравствуйте, SeLo, Вы писали:

SL>Вот в MSDN говориться что WriteByte по сути вызывает метод Write, который (извиняюсь немецкий мне роднее):


у GZipStream нет реализации ReadByte\WriteByte

ReadByte Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream. (Inherited from Stream.)
WriteByte Writes a byte to the current position in the stream and advances the position within the stream by one byte. (Inherited from Stream.)

Re[4]: Сжатие данных GZipStream
От: SeLo  
Дата: 06.04.08 10:52
Оценка:
SL>>Вот в MSDN говориться что WriteByte по сути вызывает метод Write, который (извиняюсь немецкий мне роднее):

А>у GZipStream нет реализации ReadByte\WriteByte


Если я не правильно выразился, то именно это я и имел ввиду. В Классе Stream эти методы создают массив с одним элементом и вызвают Read/Write
Re[3]: Сжатие данных GZipStream
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.04.08 10:54
Оценка: 12 (1)
Здравствуйте, SeLo, Вы писали:
S>>int blockSize = 1; // вот этим будешь играть, меняя размер блока
SL>Получается размер буфера все-таки влияет на коэффициент сжатия. Именно это мне и было интересно
Охренеть дайте две. Ты прав, посыпаю голову пеплом. Век живи, век учись.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Сжатие данных GZipStream
От: Аноним  
Дата: 06.04.08 11:28
Оценка:
Здравствуйте, SeLo, Вы писали:

Вроде понял о чем речь
Это потоковый класс, соответсвенно сколько дашь, столько и сожмёт.
О чём и говорится в описании к классу:

The compression functionality in DeflateStream and GZipStream is exposed as a stream. Data is read in on a byte-by-byte basis, so it is not possible to perform multiple passes to determine the best method for compressing entire files or large blocks of data.

Re[6]: Сжатие данных GZipStream
От: SeLo  
Дата: 06.04.08 11:43
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, SeLo, Вы писали:


А>Вроде понял о чем речь

А>Это потоковый класс, соответсвенно сколько дашь, столько и сожмёт.
А>О чём и говорится в описании к классу:
А>

А>The compression functionality in DeflateStream and GZipStream is exposed as a stream. Data is read in on a byte-by-byte basis, so it is not possible to perform multiple passes to determine the best method for compressing entire files or large blocks of data.


Это описывает лишь суть алгоритма сжатия (как и распаковки), который не предусматривает многократного прохода по данным. Данный сжимаются налету, и потому вписываются в идиалогию потоков (Stream), от которого и наследуются. Не более. Наличие буфера этот подход не исключает, без него по сути и не обходится. Вот просто выписывание сжатых данных в поток могли бы сделать регулиремым (зачем-то же Flush метод придумали). У меня вообще такое впечатление, что класс на MS не доработали. Идея хорошая, но не доработали.
Re[4]: Размер буфера
От: akasoft Россия  
Дата: 06.04.08 13:11
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Охренеть дайте две. Ты прав, посыпаю голову пеплом. Век живи, век учись.


Хм. И какой оптимальный размер буфера?
... << RSDN@Home 1.2.0 alpha 4 rev. 1074>> SQL Express 2005
Re[5]: Размер буфера
От: Sinclair Россия https://github.com/evilguest/
Дата: 07.04.08 03:39
Оценка:
Здравствуйте, akasoft, Вы писали:

A>Хм. И какой оптимальный размер буфера?

. Эксперименты не дали значительного улучшения коэффициента сжатия при увеличении объема буфера за 1 килобайт. Но размер входного окна у енкодера = 16646 байт, что бы это ни значило.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[7]: Сжатие данных GZipStream
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 07.04.08 10:11
Оценка:
Здравствуйте, SeLo, Вы писали:

SL>Это описывает лишь суть алгоритма сжатия (как и распаковки), который не предусматривает многократного прохода по данным. Данный сжимаются налету, и потому вписываются в идиалогию потоков (Stream), от которого и наследуются. Не более. Наличие буфера этот подход не исключает, без него по сути и не обходится. Вот просто выписывание сжатых данных в поток могли бы сделать регулиремым (зачем-то же Flush метод придумали). У меня вообще такое впечатление, что класс на MS не доработали. Идея хорошая, но не доработали.


Flush() это метод стрима. Идеология правильная. Сам создавай входной стрим, а уж как ты его будешь запонять это твои проблемы. Для сжатия данных нужен входящий поток и не более. Он сам будет брать данные нужными для него порциями.
и солнце б утром не вставало, когда бы не было меня
Re[3]: Сжатие данных GZipStream
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 07.04.08 10:25
Оценка: 12 (1)
Здравствуйте, SeLo, Вы писали:

SL>Но какой размер буфера? и как на этот размер влиять?


Есть замечательный классс BufferedStream, у него размер буфера можно задать в конструкторе.
... <<RSDN@Home 1.2.0 alpha 4 rev. 1074 on Windows Vista 6.0.6001.65536>>
AVK Blog
Re[8]: Сжатие данных GZipStream
От: SeLo  
Дата: 07.04.08 10:26
Оценка:
S>Flush() это метод стрима. Идеология правильная. Сам создавай входной стрим, а уж как ты его будешь запонять это твои проблемы. Для сжатия данных нужен входящий поток и не более. Он сам будет брать данные нужными для него порциями.

и...? или вы меня недопоняли, или я. какими порциями? где это регулируется? почему результыты компресси такие разные? понятно что идеалогия привильная, но вот класс этот GZip как-то криво реализованн
Re[4]: Сжатие данных GZipStream
От: SeLo  
Дата: 07.04.08 10:35
Оценка:
AVK>Есть замечательный классс BufferedStream, у него размер буфера можно задать в конструкторе.

Если я правильно вас понимаю, можно этот стрим как слой между моими компресируемыми данными и GZipStream применять? Это действительно то что нужно!

BufferedStream buffStream = new BufferedStream(compStream, 100);

int theByte = sourceFile.ReadByte();

while (theByte != -1)
{
                buffStream.WriteByte((byte)theByte);
                theByte = sourceFile.ReadByte();
}
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.