델파이/델파이관련

델파이 ZLIB 사용하기

지병철 2012. 2. 8. 16:58


[펌] [강좌] ZLIB 사용하기  c/c++ 

2005/01/10 11:35

복사http://blog.naver.com/pacho7/9145867

출처 카페 > 프로그램의 세계(http:/.. | lhs0806
원문 http://cafe.naver.com/builders/23
[강좌] ZLIB 사용하기

ZLIB 사용하기

저자: 조호석 ( laday@chollian.net )

이글은 자유롭게 배포하실 수 있습니다만, 반드시 출처를 밝혀주시기 바랍니
다. 편의상 존칭은 생략합니다.

-----------------------------------------------------------------------
1. ZLIB이란?
-----------------------------------------------------------------------

파일 압축 알고리즘중 하나로, LZW방식과 같이 가장 널리 쓰이는 방식중 하나
이다. 이전까지만 해도 LZW (LHA라는 프로그램이 이 방식을 사용함)가 많이
사용되었던 것이 사실이지만, ZLIB이 공개되면서 지금은 이 알고리즘이 많이
사용되고 있다. 누구나 자유롭게 사용할 수 있다.

ZLIB은 안정성이 입증되어있다. 안정성이란 압축한 다음 반드시 정상적으로
풀린다는 것을 보증하는 것이며 다시 같은 방식으로 압축을 시도했을 때 더이
상 압축되지 않는것을 의미한다. [당연한거 아니냐]라 할지 몰라도, 그렇지
못한 경우가 많다. 내 기억으론, 초창기 RAR방식도 이 안정성이 떨어져서 고
전을 면치 못했다. 안정성이 입증된 관계로 많은 ZIP파일 아류작들, 대표적인
것이 CAB이란 파일(윈도우 인스톨본에 쓰이는 압축 파일), 이 생겨났다. 필
자도 LZ라 하여 하나 만들어서 사용하고 있다.

재미있는 건 1.1.3버전의 ZLIB는 잘 사용되지 않는다고 한다. (어디서 들은
이야기다. No Warranty) 1.1.2버전이 주로 사용된다고 하는데, 필자의 경우는
그냥 1.1.3을 사용하였다. 남이 뭐라 해도 내가 보기엔 사용에 별 문제를 발
견하지 못했다.

어디에 쓰나? 데이터 압축 알고리즘을 어디에 쓰는지는 글쎄... 잘 모르겠다.
.. ^^; 어쨌든 이 알고리즘은 그대로 ZIP파일에 사용된다. 따라서 ZIP과 같은
포맷을 독자적으로 개발하거나, 파일 송 수신 프로토콜과 같은 경우, 그리고
암호화 까지는 되지 않아도 텍스트를 TCP를 통해 그냥 전송하긴 싫을 때 사
용하면 된다. (특히 나같은 사람은 그냥 전송하는건 무쟈게 싫어한다. 별거
아닌 데이터지만, 뭔가 걸리는게 있어서...)

-----------------------------------------------------------------------
2. 준비
-----------------------------------------------------------------------

ZLIB를 다운받자. 이곳 자료실에도 올려놓았지만 혹시모르니 URL을 적는다

http://www.base2ti.com 델파이5용 ZLIB
http://www.info-zip.org/pub/infozip/zlib/ ZLIB 공식 홈페이지

다운로드 한 후 적당한 곳에 압축을 풀자.

File -> New Application을 선택한다.

Project -> Add to Project를 선택해 ZLIB.PAS라는 파일을 추가한다. 이로써
ZLIB를 사용할 준비가 끝났다.

-----------------------------------------------------------------------
3. 압축 하기
-----------------------------------------------------------------------

이 라이브러리는 모두 스트림을 이용하는 방식으로 되어 있다. 이렇게 하면
많은 곳에 쉽게 응용이 가능하기 때문이다. 물론 속도는 조금 느리겠지만...
이 방식이 정석은 아니니, 다른 방식을 생각해 보는 것도 좋을 것이다.

압축을 하기위한 함수 CompressStream을 생각해 보자. 먼저 입력으로 받을 스
트림과 출력할 스트림, 그리고 압축한 상태를 보여주는 이벤트 핸들러가 필요
할 것이다. 따라서 프로토타입은 다음과 같은 형태를 보이게 된다.

function CompressStream(Stream: TStream; OutStream: TStream;
OnProgress: TNotifyEvent): boolean;

이제 내부코드를 생각해 보자. TZCompressionStream 이란 객체에서 압축과 관
련된 작업을 할 수 있게 되었다. 일단 이 객체를 생성시킨 후, 이벤트 핸들러
를 정해 준후, 데이터를 넣어주면 모든 것은 해결된다. 이 부분은 다음과 같
은 간단한 코드로 완성된다.

function CompressStream(Stream: TStream; OutStream: TStream;
OnProgress: TNotifyEvent): boolean;
var
   CS: TZCompressionStream;
begin
   CS := TZCompressionStream.Create(OutStream, zcMax); // 스트림 생성
try
   if Assigned(OnProgress) then CS.OnProgress := onProgress;
      CS.CopyFrom(Stream, Stream.Size); // 여기서 압축이 진행됨
                                          // 테스트 결과 압축완료시 이벤트가 발생하지 않기 때문에
                                          // 완료시 한번 더 이벤트를 불러준다.
   if Assigned(OnProgress) then onProgress(CS);
      Result := True;
   finally
      CS.Free;
   end;
end;

**************************************************************사용 방법

TForm1에 CompProgressBar: TProgressBar; 를 추가한다. (TProgressBar 컴포
넌트를 폼위에 놓고 이름을 CompProgressBar라고 변경한다)

procedure TForm1.OnCompProgress(Sender: TObject);
begin
   CompProgressBar.Position := (Sender as TZCompressionStream).Position;
end;

procedure TForm1.CompressExecute(Sender: TObject);
var
   Stream, OutStream: TFileStream;
   FN: string;
begin
   FN := 'C:\TEST.DAT';
   Stream := TFileStream.Create(FN, fmOpenRead);
   OutStream := TFileStream.Create(FN + '.zlib', fmCreate);
   try
      CompProgressBar.Max := Stream.Size;
      CompressStream(Stream, OutStream, onCompProgress);
   finally
      OutStream.Free;
      Stream.Free;
   end;
end;

-----------------------------------------------------------------------
4. 압축 풀기
-----------------------------------------------------------------------

필자가 가장 애먹었던 부분이었다. 자꾸에러가 나는 부분이라서 어떻게 해야
할지 많이 헤메었었다. 시간에 쫒기는 바람에 처음 코드는 그냥 원시적으로
해결했지만, 지금은 많이 해결되었다. 이 코드가 정석은 아니라고 생각하니
의견 있는 사람은 이 아이디로 연락주기 바란다.

출력을 위한 함수 DeCompressStream을 생각해 보면 이전에 만든 CompressStre
am과 다를 것이 없다는 생각이 들 것이다.

function DeCompressStream(Stream: TStream; OutStream: TStream;
OnProgress: TNotifyEvent): boolean;

안의 코드는 다음과 같다

function DeCompressStream(Stream: TStream; OutStream: TStream;
OnProgress: TNotifyEvent): boolean;
const BuffSize = 65535; // 버퍼 사이즈
var
   DS: TZDeCompressionStream;
   Buff: PChar; // 임시 버퍼
   ReadSize: integer; // 읽은 크기
begin
   if Stream = OutStream then
   // 입력 스트림과 출력스트림이 같으면 문제가 발생한다
   raise Exception.Create('입력 스트림과 출력 스트림이 같습니다');
   Stream.Position := 0; // 스트림 커서 초기화
   OutStream.Position := 0;
   //인풋 스트림을 옵션으로 객체 생성.
   DS := TZDeCompressionStream.Create(Stream);
   try
      if Assigned(OnProgress) then DS.OnProgress := onProgress;
      GetMem(Buff, BuffSize);
      try
      // 버퍼 사이즈만큼 읽어온다. Read함수를 부르면 압축이 풀리게 된다.
         repeat
            ReadSize := DS.Read(Buff^, BuffSize);
            if ReadSize <> 0 then OutStream.Write(Buff^, ReadSize);
         until ReadSize < BuffSize;
         if Assigned(OnProgress) then onProgress(DS); //Compress와 같은이유
         Result := True;
       finally
           FreeMem(Buff)
      end;
   finally
      DS.Free;
   end;
end;

************************************************************** 사용방법

TForm1에 DeCompProgressBar: TProgressBar; 를 추가한다. (TProgressBar 컴
포넌트를 폼위에 놓고 이름을 DeCompProgressBar라고 변경한다)

procedure TForm1.OnDeCompProgress(Sender: TObject);
begin
  DeCompProgressBar.Position:=(Sender as TZDeCompressionStream).Position;
end;

procedure TForm1.DoDeComp(FN: string);
var
   Stream, OutStream: TFileStream;
   Cursor: TCursor;
begin
   FN := 'C:\TEST.DAT.ZLIB';
   Stream := TFileStream.Create(FN, fmOpenRead)
   OutStream := TFileStream.Create(ChangeFileExt(FN, ''), fmCreate);
   try
       DeCompProgressBar.Max := Stream.Size;
      DeCompressStream(Stream, OutStream, onDeCompProgress);
   finally
      OutStream.Free;
      Stream.Free;
   end;
end;

-----------------------------------------------------------------------
5. 후기
-----------------------------------------------------------------------
도움이 되었는지 모르겠다. 좋은 라이브러리가 있는데 사용방법이 없는거 같
아 한번 올려 보았다. 아는 사람들에겐 별 필요 없는 글이 되겠지만 나같이
모르는 델피언에겐 많은 도움이 되었을 것으로 믿는다.

이 글에 의견 있다면 이곳 질문 답변란에 질문을 하거나
인터넷 메일, laday@chollian.net 로 연락주기 바란다.