Модуль для работы с bzip2 через потоки

Вопросы использования сторонних (не входящих в состав FPC и Lazarus) утилит и библиотек.

Модератор: Модераторы

Модуль для работы с bzip2 через потоки

Сообщение shade » 08.01.2007 21:11:53

bz2Stream.pas

Класс TBZStream - поток реализующий компрессию и декомпрессию методом bzip2.

При создании экземпляра TBZStream, принимает другой поток типа TStream. После чего все данные, записываемые в (считываемые из) TBZStream подвергаются преобразованию (компрессии или декомпрессии) и преобразованные данные записываются в (считываются из) TStream.

Для работы модуля требуется libbz2.dll (прилагается в архиве). Хотелось бы как-то заменить ее на чисто-паскалевкий модуль - у кого есть поделитесь (ссылкой и непосредвено самим модулем). В FCL есть fpc\packages\extra\bzip2\bzip2.pas - но, на сколько я понял он реализует только декомпрессию.

PS: писал для Delphi, так что ком пилить с опцией -Mdelphi (проверил, вроде работает).
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение SergKam » 12.01.2007 20:57:18

а нельзяли сразу добавить поддержку и других архиваторов, мне например очень нужен обычный compress который .Z файлы делает.
SergKam
постоялец
 
Сообщения: 251
Зарегистрирован: 16.11.2005 21:31:11
Откуда: Украина,Харьков

Сообщение shade » 12.01.2007 21:03:36

SergKam писал(а):а нельзяли сразу добавить поддержку и других архиваторов, мне например очень нужен обычный compress который .Z файлы делает.
Пока планируется только zLib (в аналогичном формате)
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение Sergei I. Gorelkin » 13.01.2007 00:25:02

zLib уже сто лет в обед как есть в FCL, модуль zstream.pp
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1395
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение shade » 13.01.2007 18:25:16

Sergei I. Gorelkin писал(а):zLib уже сто лет в обед как есть в FCL, модуль zstream.pp

Так это ж замечательно, не придется париться :D

Взглянул:
1. TDecompressionStream.Write - не поддерживается
2. TCompressionStream.Read - не поддерживается
3. Всего только 4 уровня компрессии (без компрессии, по минимуму, по максимуму и по умолчанию)

Но использовать можно. Надо будет как-нибудь попробовать под Delphi компильнуть...
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение Sergei I. Gorelkin » 14.01.2007 05:37:33

shade писал(а):Взглянул:
1. TDecompressionStream.Write - не поддерживается
2. TCompressionStream.Read - не поддерживается
3. Всего только 4 уровня компрессии (без компрессии, по минимуму, по максимуму и по умолчанию)

Но использовать можно. Надо будет как-нибудь попробовать под Delphi компильнуть...


хм... А что должно происходить при чтении из сжимающего потока?

В Дельфи эти классы тоже есть, только в модуле zlib.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1395
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение shade » 14.01.2007 11:15:27

Sergei I. Gorelkin писал(а):хм... А что должно происходить при чтении из сжимающего потока?
Сжатие, конечно же. Ну т.е. клиент потока должен получать сжатый контент.
Мой класс TBZStream - поддерживает все 4 варианта чтения/записи :wink:

Sergei I. Gorelkin писал(а):В Дельфи эти классы тоже есть, только в модуле zlib.

Ух ты, действительно есть, а я и не знал. Круто :!:
Почему-то в книжках по Delphi обычно зацикливаются на дизайнере форм и БД а про кучу других полезных классов забывают (или я не внимательно читаю :?: )
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение Sergei I. Gorelkin » 14.01.2007 12:45:44

shade писал(а):
Sergei I. Gorelkin писал(а):хм... А что должно происходить при чтении из сжимающего потока?
Сжатие, конечно же. Ну т.е. клиент потока должен получать сжатый контент.
Мой класс TBZStream - поддерживает все 4 варианта чтения/записи
:wink:


Ага, теперь понял, что имеется в виду. В одном классе содержится не только две противоположных операции, но еще и два принципа (тяни-толкай). На самом деле, это зря. Во-первых, правила объектно-ориентированного программирования предписывают избегать объединения непересекающейся функциональности в одном классе. Во-вторых, "противоестественное" использование чревато кучей ошибок. Например, берем несжатый поток, поверх него создаем сжимающий и начинаем оттуда читать. Как узнать, сколько нужно прочитать? Никак, единственный вариант - читать до тех пор, пока читается. А это означает, что сжать часть входного потока невозможно, только весь целиком. Освободим сжимающий поток раньше - получим убитый архив. И так далее...

shade писал(а):Ух ты, действительно есть, а я и не знал. Круто :!:
Почему-то в книжках по Delphi обычно зацикливаются на дизайнере форм и БД а про кучу других полезных классов забывают (или я не внимательно читаю :?: )


Всё в одной книжке все равно не опишешь, а Дельфи несколько ошибочно позиционируется именно как средство для быстрого накидывания кнопок на формочки...
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1395
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение shade » 14.01.2007 13:29:50

Sergei I. Gorelkin писал(а):На самом деле, это зря. ...
Ну, не знаю, не уверен.

А насчет времени, когда нужно остановиться: сам сжимающий поток определить не может определить (ни в "прямом" ни в "обратном" направлении, см. ниже), когда нужно остановиться, зато это можно сделать на основе ниже (выше) лежащего потока или иной логикой.

Таже ситуация на самом деле происходит при "прямом" использовании:
Пишем в сжимающий поток. А когда остановиться, сколько нужно записать? Ответа на данный вопрос нет, без ответа на вопрос откуда берутся данные которые нужно сжать и где они кончаются. Тоже самое и в "обратном" направлении - сначала нужно дать ответ на вопрос откуда данные. С файлами все просто - можно посмотреть на размер. А что делать с сетевым соединением?

Во-вторых, клиент сам в праве решать, что ему нужно, а что нет и соответствующим образом выбирать режим работы, может ему понадобиться "обратный" режим..
Например, у нас есть сжатый поток (который, допустим, не наследует от TStream или вообще не ООП), его нужно распаковывать и записывать в выходной поток (наследует от TStream) и TDecompressionStream.Write могла бы пригодиться но ее нет, прийдется писать обертку для нашего сжатого потока.

Во-третьих: какая такая принципиальная разница в компрессии и декомпрессии (ну кроме собственно сжатия/распаковки)?
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение Sergei I. Gorelkin » 14.01.2007 15:28:19

Когда (при "нормальном" использовании) мы пишем в сжимающий поток, мы как раз точно знаем, сколько нужно записать, потому что пишем из памяти - функцией Write. Мы не знаем, сколько получится в результате.
И при расжатии - в подавляющем большинстве случаев мы заранее знаем, сколько расжатых данных должно получиться. Если даже не знаем, то можно смело читать до EOF - библиотека декомпрессии разберется, сколько сжатых байт ей нужно, и сверх этого из сжатого потока читать не будет.
В "перевернутом" случае мы должны записывать сжатые данные до тех пор, пока не получим заданное количество расжатых. Определить же, сколько разжатых данных получилось, можно только при условии, что поток, в который они автоматом записываются, поддерживает Seek(0, soFromCurrent), что не обязано выполняться всегда. Если сжатых данных запишем больше, чем нужно, излишек вернуть невозможно.

Вот примерно поэтому "обратные" режимы в Дельфи/FPC не поддерживаются.

На случай, когда исходные данные представлены не в виде TStream, существуют THandleStream и TMemoryStream. С их помощью TStream делается в одну строчку из чего угодно.

А разница между компрессией и декомпрессией в том, что расжатые данные - "наши", мы с ними работаем, они имеют известную нам структуру и нужно иметь возможность представлять их как в виде потока, так и в виде структуры, а сжатые - просто абстрактный набор байт, представление которого не в виде потока лишено всякого смысла.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1395
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение shade » 14.01.2007 16:22:50

Sergei I. Gorelkin писал(а):THandleStream и TMemoryStream

Наследуют от TStream, я же имел в ввиду совершенно иное:
Например данные поступают в обработчике TClientSocket.OnRead
Код: Выделить всё
var buf: array of Byte;
begin
  SetLength(buf, Socket.ReceiveLength);
  Socket.ReceiveBuf(buf[0], Socket.ReceiveLength);
  DecompressToFile.write(buf[0], Socket.ReceiveLength);
end;
и все, а сколько времени вы убьете реализацию прямого подхода?

Sergei I. Gorelkin писал(а):В "перевернутом" случае мы должны записывать сжатые данные до тех пор, пока не получим заданное количество расжатых. Определить же, сколько разжатых данных получилось, можно только при условии, что поток, в который они автоматом записываются, поддерживает Seek(0, soFromCurrent), что не обязано выполняться всегда. Если сжатых данных запишем больше, чем нужно, излишек вернуть невозможно.
У вас есть сжатые данные и вы знаете их объем. Откуда излишек?

В общем, я так и не понял, чем мой подход плох, а ваш хорош. По-моему оба имеют право на существование. В конце концов, если вам не нужен TDecompressionStream.Write / TCompressionStream.Read - вы ведь можете их и не использовать, сложнее когда нужено, но нету...
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение Sergei I. Gorelkin » 15.01.2007 00:35:18

Довелось просто получить пару шишек при практическом использовании этой компрессии. Большинство пришлось как раз на ситуацию, когда сжатые данные чередовались в одном потоке с несжатыми (отсюда все мои слова об излишках).
Впрочем... действительно, не стоит спорить о вкусах.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1395
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Модуль для работы с bzip2 через потоки

Сообщение Aleh » 31.01.2017 12:28:23

Кстати по поводу шишек. Классную я набил классным классом TBZStream, точнее bzip2.dll. Её нет в 64битной версии. :(
Может у кого "пластырь" есть....
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Aleh
новенький
 
Сообщения: 53
Зарегистрирован: 08.08.2016 12:27:45

Re: Модуль для работы с bzip2 через потоки

Сообщение Aleh » 01.02.2017 12:38:32

Всё нормально! "Пластырь" здесь https://github.com/philr/bzip2-windows/releases, называется теперь libbz2.dll. Попутно выяснил, что встроенная распаковка в вин32,64 работает нормально, только на "грабли" http://www.freepascal.ru/forum/viewtopic.php?f=5&t=8597 не наступите.
Aleh
новенький
 
Сообщения: 53
Зарегистрирован: 08.08.2016 12:27:45

Re: Модуль для работы с bzip2 через потоки

Сообщение Снег Север » 01.02.2017 20:24:27

Хм... а какой смысл использовать это окаменевшее ... мамонта? Почему не 7zip уже?
Аватара пользователя
Снег Север
долгожитель
 
Сообщения: 2993
Зарегистрирован: 27.11.2007 16:14:47

След.

Вернуться в Сторонние средства

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 7

Рейтинг@Mail.ru
cron