BLOG ARTICLE 압축 궁금하니? | 2 ARTICLE FOUND

  1. 2008.05.28 ZIP 알고리즘
  2. 2008.05.28 Zlib 활용

이 문서는 http://cafe.naver.com/winmain 이 곳이라네요..
퍼왔습니다~ ^^;; 쏘리쏘리~~
 

/*

 * 파일명 : ZipTest.cpp

 * 사용법 : ZipTest [filename]

 * 압축하고자 하는 filename 입력하면 filename.zip이라는 압축파일이

 * 생성된다. 

 */

 

// 표준 C헤더파일

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

// zlib 헤더파일 

#include <zlib.h>

 

int main(int argc, char *argv[])

{

char    *filename   = NULL;

char    *gzfilename = NULL;

gzFile  zf;

int     n;

char    buf[256];

int     lerrno;

             FILE *fp;

 

if(argc !=2) {

             printf("Usage : ZipTest [file name]\n");

             exit(0);

}

filename = argv[1];

 

// 압축파일의 이름은 filename.zip 으로 한다.

gzfilename = (char *)malloc(strlen(filename)*sizeof(char));

sprintf(gzfilename, "%s.zip", filename);

 

if ((fp = fopen(filename, "rb")) == NULL) {

             printf("file open error\n");

             exit(0);   

}

 

// 압축파일을 연다.

if ((zf = gzopen(gzfilename, "wb")) == NULL) {

             exit(0);

}

 

// 원본파일을 에서 데이타를 읽어들이고

// gzwrite함수를 이용해서 데이터를 압축하고 파일에 쓴다.  

while((n = fread(buf, sizeof(char), 255, fp)) > 0)

{

if (gzwrite(zf, buf, n) < 0) {

                          printf("%s\n",gzerror(zf, &lerrno));

                          exit(0);

             }

}

 

gzclose(zf);

 

printf("compression completed : %s => %s\n", filename, gzfilename);

 

return 0;

}

앞서 만든 ZipTest 만든 압축 프로그램을 풀어주는 UnzipTest 입니다.

역시 기능 구현 테스트만을 위해 간단히 콘솔 프로그램으로 만들었고 zlib 이용했습니다..

소스는 다음과 같습니다.

 

// UnzipTest.cpp : Defines the entry point for the console application.

 

#include <stdio.h>

#include <stdlib.h>

#include <zlib.h>

 

#define BUF_SIZE 1024

 

int main(int argc, char* argv[])

{

             char *srcFileName, *destFileName;

             gzFile zfSrc;

             FILE *fpDest;

             char buf[BUF_SIZE];

             int gzr;

 

             // 파라미터가 맞지 않으면 종료

             if(argc != 3) {

                           printf("Usage: UnzipTest [source filename] [destination filename]");

                          exit(0);

             }

 

             srcFileName = argv[1];

             destFileName = argv[2];

 

             // 파일이 존재하지 않으면 종료

             if((zfSrc = gzopen(srcFileName, "rb")) == NULL) {

                           printf("can't open source file");

                           exit(0);

             }

 

             // destination 파일 열기

             if((fpDest = fopen(destFileName, "wb")) == NULL) {

                           gzclose(zfSrc);

                           printf("can't create destination file");

                           exit(0);

             }

 

             // 압축 풀기

             while((gzr = gzread(zfSrc, buf, BUF_SIZE)) > 0) {

                           fwrite(buf, sizeof(char), gzr, fpDest);

             }

 

             gzclose(zfSrc);

             fclose(fpDest);

 

             // 에러발생시 종료

             if(gzr < 0) {

                           printf("Error occured.");

                           exit(0);

             }

 

             printf("Decompression completed.");

             return 0;

}

 

 

 

일단 기본적인 압축 압축 푸는 기능은 구현할 있게 되었습니다. 하지만 여러 파일(폴더 포함) 하나의 압축파일로 묶어서 압축하는 어떻게 해야 할지 아직까지는 모르겠군요. 좀더 연구를 해보야야겠습니다.


앞서 만든 두개의 ZipTest, UnzipTest 프로그램은 zip 압축 프로그램이 아니라 gz 압축 프로그램이었다. 첨엔 zlib가 zip 압축을 위한 라이브러리인줄 알았으나 사실은 gz 압축용 라이브러리였던 것이다. 이런..

(혹시 믿고 따라하신 분이 계셨다면 정말로 사과의 말씀드립니다. 사실 저도 몰랐답니다. ㅠㅠ)

 

그렇다면 zlib는 zip 압축을 지원하지 않는가? http://zlib.net 의 FAQ에서는 다음과 같이 대답해주고 있다.

 

Can zlib handle .zip archives?

 

Not by itself, no. See the directory contrib/minizip in the zlib distribution.

 

Not by itself 라니, 이 무슨 애매모호한 대답인가. -_-; 하지만 이 대답과 기타 여러 정황(?)으로 볼때 zip과 gz은 전혀 상관 없는 것도 아니라는 것이다. http://www.winimage.com/zLibDll/unzip.html 를 보면 이런 말이 나온다.

 

Using Unzip package
The Unzip source is only two file : unzip.h and unzip.c. But it use the Zlib files.

miniunz.c is a very simple, but real unzip program (display file in zipfile or extract them).

 

Using Zip package
The Zip source is only two file : zip.h and zip.c. But it use the Zlib files.

minizip.c is a very simple, but real zip program.

 

zip과 unzip 기능을 해주는 소스는 내부적으로 zlib를 이용한다고 한다. 이런 추리가 가능하다. gz은 단순 파일 압축이며, zip은 zlib 등의 gz 압축 알고리즘을 이용하되 이를 다수의 파일 및 폴더에 대한 압축이 가능하도록 만든 것이다라는.. 물론 틀린 추론일 수도 있다. -.-;

 

하지만 분명한 것은 Gilles Vollant가 만든 minizip의 네개의 소스 zip.h, zip.c, unzip.h, unzip.c를 이용하면 zip 압축 기능의 구현이 가능할 것이라는 사실이다.

 

헌데 여기서 한가지 문제가 있다. zip.c, unzip.c 라는 파일명을 보아도 알수 있지만 이것은 C++이 아닌 C로 쓰여진 프로그램이라는 것이다. 물론 VC++에서 C 컴파일이 가능하지만, 이를 C++로 래핑(wrapping)해 놓은 소스가 있다.

 

http://www.codeproject.com/cpp/zipunzip.asp 이곳에서 얻을 수 있을 것이다. Win32 Wrapper classes for Gilles Volant's Zip/Unzip API 라는 제목의 Zip/Unzip API란 바로 위에서 소개한 zip.h, unzip.h에서 찾을 수 있는 API들일 것이다. 이것을 Daniel Godson이라는 사람이 친절하게도 Win32 버전으로 래핑해놓은 것이다.


Win32 Wrapper classes for Gilles Volant's Zip/Unzip API 클래스 CZipper CUnzipper public 메소드 원형입니다.

 

class CZipper 

{

public:

CZipper(LPCTSTR szFilePath = NULL, LPCTSTR szRootFolder = NULL, bool bAppend = FALSE);

             virtual ~CZipper();

 

// simple interface

static bool ZipFile(LPCTSTR szFilePath); // saves as same name with .zip

static bool ZipFolder(LPCTSTR szFilePath, bool bIgnoreFilePath); // saves as same name with .zip

 

// works with prior opened zip

bool AddFileToZip(LPCTSTR szFilePath, bool bIgnoreFilePath = FALSE);

bool AddFileToZip(LPCTSTR szFilePath, LPCTSTR szRelFolderPath); // replaces path info from szFilePath with szFolder

bool AddFolderToZip(LPCTSTR szFolderPath, bool bIgnoreFilePath = FALSE);

 

// extended interface

bool OpenZip(LPCTSTR szFilePath, LPCTSTR szRootFolder = NULL, bool bAppend = FALSE);

bool CloseZip(); // for multiple reuse

void GetFileInfo(Z_FileInfo& info);

};

 

 

class CUnzipper 

{

public:

CUnzipper(LPCTSTR szFilePath = NULL);

virtual ~CUnzipper();

 

// simple interface

static bool Unzip(LPCTSTR szFileName, LPCTSTR szFolder = NULL, bool bIgnoreFilePath = FALSE);

 

// works with prior opened zip

bool Unzip(bool bIgnoreFilePath = FALSE); // unzips to output folder or sub folder with zip name

bool UnzipTo(LPCTSTR szFolder, bool bIgnoreFilePath = FALSE); // unzips to specified folder

 

// extended interface

bool OpenZip(LPCTSTR szFilePath);

bool CloseZip(); // for multiple reuse

bool SetOutputFolder(LPCTSTR szFolder); // will try to create

 

// unzip by file index

int GetFileCount();

bool GetFileInfo(int nFile, UZ_FileInfo& info);

bool UnzipFile(int nFile, LPCTSTR szFolder = NULL, bool bIgnoreFilePath = FALSE);

 

             // unzip current file

bool GotoFirstFile(LPCTSTR szExt = NULL);

bool GotoNextFile(LPCTSTR szExt = NULL);

bool GetFileInfo(UZ_FileInfo& info);

bool UnzipFile(LPCTSTR szFolder = NULL, bool bIgnoreFilePath = FALSE);

 

// helpers

bool GotoFile(LPCTSTR szFileName, bool bIgnoreFilePath = TRUE);

bool GotoFile(int nFile);

};

CZipper 대해서는 약간의 추가 설명을 찾을수 있었습니다.

출처 http://www.codeproject.com/cpp/zipunzip.asp

 

The CZipper class interface provides two approaches to zipping:

1.     For simple file and folder zipping, you can use the static ZipFile(...) or ZipFolder(...) methods.

2.     For more complex zipping requirements, you can alternatively instantiate a CZipper object, then use OpenZip(...), followed by one or more AddFileToZip(...) or AddFolderToZip(...) calls, before ending with CloseZip().

 

CZipper 클래스 인터페이스는 zip 압축에 대한 방법을 제공한다.

1. 한개의 파일이나 폴더 압축을 하려면, 정적 메소드 ZipFile(...) ZipFolder(...) 사용하면 된다.

2. 좀더 복잡한 zip 압축을 하고 싶다면, CZipper 인스턴스를 생성한 , OpenZip(...) 호출하고, AddFileToZip(...)이나 AddFolderToZip(...) 사용하여 파일이나 폴더를 추가하고, CloseZip()으로 마무리한다.


zip 통합 라이브러리를 만들었습니다.

 

http://zlib.net  zlib,

Gilles Volant Zip/Unzip API,

Daniel Godson Win32 Wrapper 클래스를 모두 모아 컴파일하여 통합 라이브러리로 만들었습니다.

 

각각의 API  해당하는 헤더 파일은 관련 사이트에서 소스를 받으시면 함께 받으실 있을 겁니다. 윈도우에서의 간단한 zip 압축 구현을 위해서라면 Daniel Godson 소스중 Zipper.h, Unzipper.h 있어도 것입니다.


앞에서 만든 zip 통합 라이브러리 zipunzip.lib 이용한 zip 압축 프로그램입니다.

역시 기능 구현 테스트를 위하여 간단히 콘솔 프로그램으로 만들었습니다.

 

소스는 다음과 같습니다.

 

// SimpleZip.cpp : Defines the entry point for the console application.

// Usage: SimpleZip [flag] [source file]

//        flag: c - compress

//               d - decompress

 

#include <stdio.h>

#include <windows.h>

#include <zipper.h>

#include <unzipper.h>

 

int main(int argc, char* argv[])

{

             char *srcFileName;

             bool bSrcIsDirectory, br;

             DWORD fileAttr;

 

             // 파라미터 확인

             if(argc != 3) {

                           printf("Usage: SimpleZip [flag] [source file]\n");

                           printf("       flag: c - compress\n");

                           printf("             d - decompress");

                           exit(0);

             }

 

             srcFileName = argv[2];

 

             // 소스 파일 확인

             bSrcIsDirectory = ((fileAttr = GetFileAttributes(srcFileName)) & FILE_ATTRIBUTE_DIRECTORY) > 0;

             if(fileAttr == 0xFFFFFFFF) {

                           printf("file not exist or has unknown problems");

                           exit(0);

             }

 

             switch(argv[1][0]) {

             case 'c':

             case 'C':

                           // 디렉토리인 경우

                           if(bSrcIsDirectory) {

                                        br = CZipper::ZipFolder(srcFileName, FALSE);

                           }

                           // 파일인 경우

                           else {

                                        br = CZipper::ZipFile(srcFileName);

                           }

 

                           printf(br ? "compression completed." : "error occured.");

                           break;

                          

             case 'd':

             case 'D':

                           // 디렉토리인 경우

                           if(bSrcIsDirectory) {

                                        printf("%s isn't a file", srcFileName);

                                        exit(0);

                           }

                           // 파일인 경우

                           else {

                                        CUnzipper uz;

                                        br = uz.OpenZip(srcFileName);

                                        if(br) br = uz.UnzipTo(".");

                                        printf(br ? "decompression completed." : "error occured.");

                           }

                           break;

 

             default:

                           printf("wrong flag.");

                           break;

             }

 

             return 0;

}

Posted by ΣUΝ
AND

Zlib 활용

압축 궁금하니? 2008. 5. 28. 11:08
출처: http://www.joinc.co.kr/modules/moniwiki/wiki.php/article/zlib_prog

Zlib 활용

윤 상배

dreamyun@yahoo.co.kr

고친 과정
고침 0.8 2003년 10월 2일 23시
최초 문서작성

차례
1. 소개
2. Zlib를 이용한 압축 프로그래밍
2.1. 유틸리티 함수설명
2.1.1. compress
2.1.2. compress2
2.1.3. uncompress
2.1.4. gzopen
2.1.5. gzdopen
2.1.6. gzsetparams
2.1.7. gzread
2.1.8. gzwrite
2.1.9. int VAgzprintf
2.1.10. gzputs
2.1.11. gzgets
2.1.12. gzputc
2.1.13. gzgetc
2.1.14. gzfluseh
2.1.15. gzseek
2.1.16. gzrewind
2.1.17. gzeof
2.1.18. gzclose
2.1.19. gzerror
2.1.20. zlibVersion
2.2. 예제
2.2.1. 파일 압축 예제
2.2.2. 압축 해제 예제
2.3. 네트워크 애플리케이션에서의 활용

1. 소개

PC와 인터넷의 보급으로 데이터의 양이 급증하고 있다. 그러다 보니 데이터 저장공간에 많은 압박을 받게 된다. 거기에 더불어 인터넷이 대중화 되면서 데이터를 전송하기 위한 네트워크자원에의 압박도 받게 되었다.

이런 문제를 해결하기 위해서 개발된게 데이터 압축기술이며, Zlib는 범용적인 데이터의 압축을 위한 목적으로 개발되었다. 이 문서는 Zlib를 설명하기 위한 목적으로 작성되었으며, 레퍼런스 용도로써 유용하게 사용가능 할것이다. 또한 문서의 마지막에 간단한 활용예제를 둠으로써 좀더 쉽게 이해하도록 배려하고 있다.

이 문서의 많은 내용들은 Zlib레퍼런스 메뉴얼을 참고 하고 있다.


2. Zlib를 이용한 압축 프로그래밍

이번장에서는 Zlib에 대한 개략적인 소개와 함께 Zlib에서 제공하는 각종 함수에 대해서 다루게 된다. 그러나 모든 함수들에 대해서는 다루지 않고 프로그래밍 하는데 필요한 필수 함수들만을 다룰 것이다. 이외에도 zlib에서 제공되는 함수들이 있는데, 일반적인 응용 애플리케이션의 제작에는 거의 사용되지 않는 함수들이다. 이들 함수들에 대한 자세한 설명은 Zlib레퍼런스 메뉴얼를 참고하기 바란다.

지금은 단지 자주 사용되는 유틸리티 함수들만 설명하고 있는데, 시간이 된다면 zlib에서 제공하는 다른 함수들에 대해서도 설명하도록 하겠다. (zlib에서는 크게 유틸리티 함수, 기본 함수, 고급 함수 세개로 분류되어서 설명하고 있다.)


2.1. 유틸리티 함수설명

유틸리티 함수들은 말 그대로 응용 애플리케이션 레벨에서 간단하게 사용할 수 있는 높은 수준의 함수들로써 다음장에 설명하게될 기본함수들의 응용함수들이다.

높은 수준의 함수들인 만큼 사용하기 편하고 대부분의 압축작업을 하는데 있어서 여기에서 제공하는 것들로 충분할 것이다.

함수들을 살펴보면 알겠지만 파일관련 작업을 위해 사용되는 함수들과 이름이나 쓰임새가 매우 비슷하다는걸 알 수 있을 것이다. 기존의 표준적인 함수들과 비슷한 인터페이스를 유지하므로써 함수를 이해하고 사용하기가 좀더 수월하다.


2.1.1. compress

int compress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
				
이름에서 알 수 있듯이 데이터를 압축하기 위해서 사용된다. source데이터를 sourceLen크기 만큼 압축을 해서 dest 버퍼로 복사한다. destLen은 dest버퍼의 총 크기인데, 최소한 sourceLen 0.1%정도 크게 잡아 주어야 한다. 압축을 실시할 경우 반드시 데이터의 크기가 작아질 거라고 생각할 수 있겠지만 오히려 커지는 경우도 생길 수 있기 때문이다. 매우 작은 데이터를 압축하거나 이미 압축된 데이터를 압축하는 경우 압축된 데이터에 zlib헤더가 붙어서 오히려 데이터의 양이 더 커질 수도 있다.

compress는 성공적으로 압축되었을 경우 Z_OK를 메모리가 충분하지 않을경우 Z_MEM_ERROR, 버퍼의 크기가 충분하지 않을경우 Z_BUF_ERROR를 리턴한다.


2.1.2. compress2

int compress2(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level);
				
level이란 인자가 추가된것 외에는 compress와 완전히 동일하다. level은 압축의 정도를 결정하기 위해서 사용하는 것으로 0에서 9사이의 값을 가진다. 0은 가장 빠른 압축시간을 보여주며 9는 최고의 압축률을 보여준다. 만약 level을 0으로 하였다면 전혀 압축을 하지 않는다는 의미로 데이터 복사를 하는 것과 동일한 효과를 보여준다.

리턴값은 commpress와 완전히 동일함으로 참고하기 바란다.


2.1.3. uncompress

int uncompress(Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen); 
				
압축된 데이터의 압축을 풀기 위해서 사용한다. 압축된 데이터 source를 sourceLen길이만큼 읽어서 압축을 해제한다음 dest버퍼에 저장한다. destLen는 dest버퍼의 크기로 압축이 풀릴 데이터의 크기를 예상해서 충분히 크게 잡아야 한다. 압축을 해제하는 작업이 성공적으로 이루어졌다면 실제 압축이 풀린 데이터의 크기가 destLen에 들어가게 된다.

성공적으로 수행되었을 경우 Z_OK가 리턴되며, 메모리가 충분치 않을경우 Z_MEM_ERROR, 버퍼의 크기가 충분치 않을 경우 Z_BUF_ERROR, 압축데이터가 잘못되어 있을 경우 Z_DATA_ERROR을 리턴한다.


2.1.4. gzopen

typedef voidp gzFile;

gzFile gzopen(const char *path, const char *mode);
				
압축된 데이터를 읽거나 쓰기 위해서 gzip파일을 연다. 두번째 인자인 mode는 "rb", "wb"등이 사용된다. 파일이 압축포멧된 파일이 아니더라도 상관은 없다. 성공적으로 파일을 열었을경우 gzFile를 리턴하는데, 압축파일 스트림으로 gzread, gzwrite등의 함수를 이용해서 실질적인 압축작업을 할때 (파일지정자)처럼 사용된다.

파일을 열기에 실패했을 경우 NULL을 리턴한다.


2.1.5. gzdopen

gzFile gzdopen(int fd, const char *mode);
				
열고자 하는 파일의 이름이 들어가는 대신 파일 지정자가 들어간다는 것만을 제외하고는 gzopen과 동일하게 작동한다. 파일지정자는 open, creat, pipe, filno등으로 생성된다.

실패했을 경우 NULL을 리턴한다.


2.1.6. gzsetparams

int gzsetparams(gzFile file, int level, int strategy);
				
동적으로 압축레벨(level)과 압축정책(strategy)을 변경하기 위해서 사용된다. level은 압축률을 지정하기 위해서 사용된다.

압축정책은 Z_DEFAULT_STRATEGY와 Z_FILTERED, Z_HUFFMAN_ONLY 중 하나를 선택할 수 있다.

성공했을 경우 Z_OK를 실패했을 경우 Z_STREAM_ERROR을 리턴한다.


2.1.7. gzread

int gzread(gzFile file, voidp buf, unsigned len);
				
압축파일 스트림 file로 부터 len크기만큼 읽어서 압축을 푼다음 buf에 저장한다. 만약 파일이 gzip 포맷이 아닐경우 단순히 데이터를 복사한다.

성공했을 경우 압축풀린 데이터의 크기를 되돌려준다. 파일의 끝일 경우 0을 그밖의 에러에 대해서는 -1을 리턴한다.


2.1.8. gzwrite

int gzwrite (gzFile file, const voidp buf, unsigned len);
				
buf로 부터 len크기만큼 데이터를 읽어들여서 압축을 한다음 file에 쓴다. 성공적으로 수행되었다면 입력된 원본 데이터의 크기가 리턴되고, 실패 했을 경우 0이 리턴된다.


2.1.9. int VAgzprintf

int VAgzprintf(gzFile file, const char *format, ...); 
				
포맷 저장을 위한 fprintf(3)를 알고 있을 것이다. 이 함수는 fprintf의 압축버젼이라고 할만하다. 포맷을 받아서 압축한다음에 저장한다. 성공했을 경우 압축에 사용된 데이터의 크기를 리턴하고 실패했을 경우 0을 리턴한다.


2.1.10. gzputs

int gzputs(gzFile file, const char *s);
				
널이 제거된 문자열을 받아들여서 압축한다.

성공했을 경우 문자열의 크기를 그렇지 않을 경우 -1을 리턴한다.


2.1.11. gzgets

char *gzgets(gzFile file, char *buf, int len);
				
압축파일 스트림 file로 부터 데이터를 읽어들여서 압축을 푼다음 문자열을 되돌려준다. 데이터를 읽을 때는 len - 1만큼을 읽어 들이며 개행문자를 만나면 리턴시킨다. fgets(3)의 압축버젼이다.

실패 했을경우 Z_NULL을 리턴한다.


2.1.12. gzputc

int gzputc(gzFile file, int c);
				
문자 c를 unsigned char로 변경한다음 file로 저장한다. 성공하면 입력한 값을 리턴하고 실패했을 경우 -1을 리턴한다.


2.1.13. gzgetc

int gzgetc(gzFile file);
				
압축파일로 부터 1바이트를 읽어들인다. 성공하면 읽어들인 값을 리턴하고 파일의 끝을 만났거나 실패했을 경우 -1을 리턴한다.


2.1.14. gzfluseh

int gzflush(gzFile file, int flush);
				
출력대기 중인 모든 데이터를 파일에 쓴다.

성공했을 경우 Z_OK를 리턴한다.


2.1.15. gzseek

z_off_t gzseek(gzFile file, z_off_t offset, int whence);
				
file에서 gzread나 gzwrite를 이용할 시작 위치를 지정하기 위해서 사용한다. lseek(2)와 비슷하다고 볼수 있다. offset은 압축이 풀린 데이터의 변위를 가르킨다. whencelseek(2)에서와 동일한 값을 사용할 수 있지만 SEEK_END가 지원되지 않는다. whence에 대해서 자세히 알길 원한다면 lseek를 이용한 파일내 위치이동를 참고하기 바란다.

이 함수는 압축된 파일내에서 위치이동을 하는게 아닌 압축이 풀린 데이터내에서의 위치이동을 하게 되므로, 파일이 읽기 위해서 열려 있는 경우 극도로 느리게 작동할 것이다. 만약 파일이 쓰기 위해서 열려 있다면 단지 전방향 이동(forward seek)만 허용 된다.

성공했을 경우 압축이 풀린 데이터의 시작지점에서의 변위값을 되돌려주고 실패 했을경우 -1을 리턴한다.


2.1.16. gzrewind

int gzrewind(gzFile file);
				
파일을 처음으로 되돌린다. 읽기모드로 열었을 때만 사용가능하다. gzrewind(file)는 gzseek(file, 0L, SEEK_SET)와 동일하다.


2.1.17. gzeof

int gzeof(gzFile file);
				
파일에서 끝을 만날경우 1을 리턴한다. 그렇지 않을경우 0을 리턴한다.


2.1.18. gzclose

int gzclose(gzFile file);
				
압축과 관련된 모든 작업이 끝나고 Fluseh까지 성공적으로 수행했다면, gzclose를 호출해서 압축된 파일을 닫고 모든 자원을 해제 해야 한다.


2.1.19. gzerror

const char * gzerror(gzFile file, int *errnum);
				
마지막 에러에 대한 에러 메시지를 되돌려준다. errnum은 zlib에서 사용하는 에러번호다. 만약 에러가 zlib가 아닌 다른 (예를 들어서 파일 시스템)곳에서 발생한 것이라면 errnum은 Z_ERRNO로 채워진다. 이때는 errno를 검사 하도록 한다.


2.1.20. zlibVersion

const char *zlibVersion(void);
				
애플리케이션이 사용하는 zlib버젼을 확인하기 위해서 사용한다. 만약 애플리케이션의 zlib버젼과 zlib.h에 선언된 ZLIB_VERSION버젼의 첫글자가 틀리다면 이 애플리케이션은 zlib호환 문제로 사용할 수 없게된다.

다음과 같은 방법으로 버젼호환여부를 체크할 수 있을 것이다.

...
if (strncmp(zlibVersion(), ZLIB_VERSION, 1) != 0)
{
	printf("Version error\n");
	exit(1);
}
...
				


2.2. 예제

2개의 예제파일을 준비했다. 하나는 특정파일을 압축하는 프로그램이고 또다른 하나는 압축된 파일의 원문 내용을 출력하는 프로그램이다. 매우 간단한 소스 이므로 설명은 주석으로 대신하도록 하겠다.


2.2.1. 파일 압축 예제

예제 : jzip.c

/*
 * 파일명 : jzip.c 
 * 사용법 : # jzip [filename]
 * 압축하고자 하는 filename를 입력하면 filename.gz이라는 압축파일이 
 * 생성된다.  
 */

// zlib 헤더파일  
#include <zlib.h>

// 표준 C헤더파일
#include <stdio.h>
#include <fcntl.h>

int main(int argc, char **argv)
{
    char    *filename   = NULL;
    char    *gzfilename = NULL;

    gzFile  *zfp;
    int     fd;
    int     n;
    char    buf[256];
    int     lerrno;

    if(argc !=2)
    {
        printf("Usage : jzip [file name]\n"); 
        exit(0);
    }
    filename = argv[1];
    // 압축파일의 이름은 filename.gz 으로 한다. 
    gzfilename = (char *)malloc(strlen(filename)*sizeof(char));
    sprintf(gzfilename, "%s.gz", filename);

    // 압축원본 파일이 존재하는지 확인한다. 
    if (access(filename, F_OK) != 0) 
    {
        printf("존재하지 않는 파일입니다\n");
        exit(0);
    }

    if ((fd = open(filename, O_RDONLY)) < 0)
    {
        printf("file open error\n");
        exit(0);    
    }

    // 압축파일을 연다. 
    if ((zfp = gzopen(gzfilename, "wb")) == NULL)
    {
        exit(0);
    }

    // 원본파일을 에서 데이타를 읽어들이고 
    // gzwrite함수를 이용해서 데이터를 압축하고 파일에 쓴다.   
    while((n = read(fd, buf, 255)) > 0)
    {
        if (gzwrite(zfp, buf, n) < 0)
        {
            printf("%s\n",gzerror(zfp, &lerrno));
            exit(0);
        }
    }
    gzclose(zfp);
    printf("압축 성공 : %s => %s\n", filename, gzfilename);
}
				
컴파일 할 때는 반드시 zlib를 링크 시켜줘야 한다.
# gcc -o jzip jzip.c -lz
				


2.2.2. 압축 해제 예제

이번 프로그램은 압축된 text문서의 원래 내용을 보여주는 간단한 프로그램이다.

예제 : jcat.c

#include <zlib.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    char *filename = NULL;

    gzFile *zfp;
    char buf[1024];

    if (argc != 2)
    {
        printf("Usage : jcat [file name]\n");
        exit(0);
    }
    filename = argv[1];

    if ((zfp = gzopen(filename, "rb")) == NULL)
    {
        exit(0);
    }

    while(gzgets(zfp, buf, 1023) != NULL)
    {
        printf("%s", buf);
    }

    gzclose(zfp);
}
				


2.3. 네트워크 애플리케이션에서의 활용

zlib는 일반 파일을 압축하기 위한 용도로 매우 훌륭한 도구이긴 하지만 인터넷을 통해 대량의 정보를 보내는 요즘에는 특히 네트워크에서의 데이터 압축을 위해서도 중요하게 사용된다.

대부분의 웹서버와 웹클라이언트는 zlib를 이용해서 자체적으로 필요한 데이터를 압축하고 해제하면서 가능한한 네트워크의 자원을 효율적으로 사용할 수 있도록 작성되어지고 있다. 공용으로 사용되는 네트워크 보다는 아무래도 개인이 사용하는 PC의 (CPU)자원을 활용하는게 여러모로 효율적이기 때문이다.

네트워크 애플리케이션에서 데이터를 압축시켜서 전송하기 위해서는 uncompress, compress등의 압축명령을 주로 사용한다. 이들 내용에 대해서는 자세히 다루지 않을 것이다. 직접 구현해보는 것도 매우 재미있을 것이다.

AND