zip IO 핸들링


miniZip 라이브러리는 기본적으로 파일 IO 기반으로 만들어졌지만, 필요하면 사용자가 직접 IO를 핸들링할 수 있습니다. 사용자 IO 핸들링을 위해 함수 포인터로 구성된 구조체를 지원하면, 세부적인 구현 방식은 stdio에 있는 파일 IO와 유사한 규약을 따릅니다.

사용자 IO 핸들링을 사용하면 파일 형태로 저장하지 않고, 버퍼 레벨에서 압축하거나 압축된 결과를 해제할 수 있습니다.

예를 들어서 서버가 메모리 레벨에서 연산된 데이터를 메모리 레벨에서 압축한후 클라이언트로 보낼 수 있습니다. 또한 클라이언트는 서버에서 전달된 데이터를 파일 형태로 저장하지 않고, 메모리 레벨에서 압축해제한 후 내부 데이터를 사용할 수 있게 됩니다.

 

——-기반 클래스 만들기——–

Z_IO_Base.h 파일
#pragma  once

#include  <LibZ/ioapi.h>

class  Z_IO_Base:public  zlib_filefunc64_def
{
public:
    Z_IO_Base(void);
    ~Z_IO_Base(void);

private:
   virtual  voidpf open(const  void* filename, int mode)=0;
   virtual  ZPOS64_T tell()=0;
   virtual  long seek(ZPOS64_T offset, int origin)=0;
   virtual  int close()=0;

   //압축을  풀때
   virtual  uLong read(void* buf, uLong size);

   //압축할 
   virtual  uLong write(const  void* buf, uLong size);
   virtual  int error();

private:
   static  voidpf open_fn(voidpf opaque, const  void* filename, int mode);
   static  uLong read_fn(voidpf opaque, voidpf stream, void* buf, uLong size);
   static  uLong write_fn(voidpf opaque, voidpf stream, const  void* buf, uLong size);
   static  ZPOS64_T tell_fn(voidpf opaque, voidpf stream);
   static  long seek_fn(voidpf opaque, voidpf stream, ZPOS64_T offset, int origin);
   static  int close_fn(voidpf opaque, voidpf stream);
   static  int error_fn(voidpf opaque, voidpf stream);
};

Z_IO_Base.cpp 파일
#include  "Z_IO_Base.h"


Z_IO_Base::Z_IO_Base(void)
{
   this->opaque = this;
   this->zopen64_file = Z_IO_Base::open_fn;
   this->zread_file = Z_IO_Base::read_fn;
   this->zwrite_file = Z_IO_Base::write_fn;
   this->ztell64_file = Z_IO_Base::tell_fn;
   this->zclose_file = Z_IO_Base::close_fn;
   this->zerror_file = Z_IO_Base::error_fn;
   this->zseek64_file = Z_IO_Base::seek_fn;
}


Z_IO_Base::~Z_IO_Base(void)
{
}


voidpf 
Z_IO_Base::open_fn(voidpf  opaque, const  void* filename, int  mode){
   Z_IO_Base* obj= (Z_IO_Base*)opaque;
   return obj->open(filename, mode);
}

uLong 
Z_IO_Base::read_fn(voidpf  opaque, voidpf  stream, void* buf, uLong  size){
   Z_IO_Base* obj= (Z_IO_Base*)opaque;
   return obj->read(buf, size);
}

uLong 
Z_IO_Base::write_fn(voidpf  opaque, voidpf  stream, const  void* buf, uLong  size){
   Z_IO_Base* obj= (Z_IO_Base*)opaque;
   return obj->write(buf, size);
}

int 
Z_IO_Base::close_fn(voidpf  opaque, voidpf  stream){
   Z_IO_Base* obj= (Z_IO_Base*)opaque;
   return obj->close();
}


ZPOS64_T
Z_IO_Base::tell_fn(voidpf  opaque, voidpf  stream){
   Z_IO_Base* obj= (Z_IO_Base*)opaque;
   return obj->tell();
}

long 
Z_IO_Base::seek_fn(voidpf  opaque, voidpf  stream, ZPOS64_T  offset, int  origin){
   Z_IO_Base* obj= (Z_IO_Base*)opaque;
   return obj->seek(offset, origin);
}


int 
Z_IO_Base::error_fn(voidpf  opaque, voidpf  stream){
   Z_IO_Base* obj= (Z_IO_Base*)opaque;
   return obj->error();
}

uLong 
Z_IO_Base::read(void* buf, uLong  size){
   return  size;
}

uLong 
Z_IO_Base::write(const  void* buf, uLong  size){
   return  size;
}

int 
Z_IO_Base::error(){
   return 0;
}

– 압축풀 때 IO 핸들링하기–

UnzipCTL.h 파일
#pragma  once
#include  <LibZ/unzip.h>
#include  <string>

#include  <fstream>


#include  "Z_IO_Base.h"

class UnzipCTL:public Z_IO_Base
{
private:
    std::ifstream fp_;

    unzFile uf_;



public:
   explicit UnzipCTL(const  char* filename);
    ~UnzipCTL(void);
   void extractall(std::string root_folder);

private:
   void mkfolder(std::string filepath);

   virtual voidpf open(const  void* filename, int mode);
   virtual  int close();
   virtual ZPOS64_T tell();
   virtual  long seek(ZPOS64_T offset, int origin);
   virtual uLong read(void* buf, uLong size);
};

UnzipCTL.cpp 파일
#include  "UnzipCTL.h"
#include  <direct.h>
#include  <Windows.h>
#include  <iostream>

UnzipCTL::UnzipCTL(const  char* filename)
    :uf_( unzOpen2_64(filename,this) )
{
}


UnzipCTL::~UnzipCTL(void)
{
    unzClose(uf_);
}


voidpf
UnzipCTL::open(const  void* filename, int mode){
    fp_.open(( const  char*)filename, std::ios_base::binary);
   return &fp_;
}

int 
UnzipCTL::close(){
    fp_.close();
   return 0;
}

ZPOS64_T
UnzipCTL::tell(){
   return fp_.tellg();
}

long 
UnzipCTL::seek(ZPOS64_T offset, int origin){
    fp_.seekg(offset, origin);
   return 0;
}

uLong
UnzipCTL::read(void* buf, uLong size){
    fp_.read((char*)buf, size);
   return fp_.gcount();
}

void 
UnzipCTL::mkfolder(std::string filepath){
    std::string sfolder;
   for(auto& item:filepath){
      if('==item){
          _mkdir(sfolder.c_str());
      }
       sfolder.push_back(item);
   }
}

void 
UnzipCTL::extractall(std::string root_folder){
   int ret=unzGoToFirstFile(uf_);
   if( UNZ_OK!=ret) return;
    mkfolder(root_folder+"\\");

    unz_file_info info;
   const  int MAX_NAME=256;
   char filename[MAX_NAME];

    std::string filepath;

   const  int BUF =1024;
   char in[BUF];
    size_t readsize(0);
    DWORD wsize(0);

    SYSTEMTIME stime;
    memset(&stime,0,sizeof(SYSTEMTIME));

    FILETIME ltime,ftime;

   do {
       unzGetCurrentFileInfo(uf_,&info,filename,MAX_NAME,NULL,0,NULL,0);

       filepath = root_folder+filename;
       mkfolder(filepath);

       HANDLE hfile = CreateFileA(filepath.c_str(),GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
      if( INVALID_HANDLE_VALUE == hfile) continue;

       unzOpenCurrentFile(uf_);
      do{
          readsize= unzReadCurrentFile(uf_,in,BUF);
          info.uncompressed_size -=readsize;
          wsize=0;
          WriteFile(hfile,in,readsize,&wsize,NULL);

      } while( 0!=info.uncompressed_size);
       unzCloseCurrentFile(uf_);

       stime.wHour = info.tmu_date.tm_hour;
       stime.wDay = info.tmu_date.tm_mday;
       stime.wMinute = info.tmu_date.tm_min;
       stime.wMonth = info.tmu_date.tm_mon+1;
       stime.wSecond = info.tmu_date.tm_sec;
       stime.wYear = info.tmu_date.tm_year;

       SystemTimeToFileTime(&stime,<ime);
       LocalFileTimeToFileTime(<ime, &ftime);
       SetFileTime(hfile,&ftime,&ftime,&ftime);
       CloseHandle(hfile);

       std::cout<<std::endl<<filepath.c_str()<<"Complete Uncompress!!";

   } while(UNZ_OK==unzGoToNextFile(uf_) );

}

ZIO_unzip.cpp 파일
// ZIO_unzip.cpp : Defines the entry point for the console application.
//

#include  "stdafx.h"

#include  "UnzipCTL.h"

int  _tmain(int  argc, _TCHAR* argv[])
{
   UnzipCTL ctl("test.zip");
    ctl.extractall("iodata");

   return 0;
}

—– 압축할 때 IO 핸들링하기–

ZipCTL.h 파일
#pragma  once

#include  <LibZ/zip.h>
#include  "FolderList.h"
#include  "Z_IO_Base.h"
#include  <fstream>

class  ZipCTL:public  Z_IO_Base
{
private:
    std::ofstream fp_;

   zipFile zf_;


public:
   explicit ZipCTL(const  char* zipfilename, int append = APPEND_STATUS_CREATE);
    ~ZipCTL(void);

   void make(const  char* root_folder, FolderList::ZIP_FLIST& mlist);

private:
   virtual  voidpf open(const  void* filename, int mode);
   virtual  int close();
   virtual  ZPOS64_T tell();
   virtual  long seek(ZPOS64_T offset, int origin);
   virtual  uLong write(const  void* buf, uLong size);
};

ZipCTL.cpp 파일
#include  "ZipCTL.h"
#include  <fstream>
#include  <iostream>

ZipCTL::ZipCTL(const  char* zipfilename, int  append)
    :zf_( zipOpen2_64(zipfilename, append,NULL, this) )
{
}


ZipCTL::~ZipCTL(void)
{
    zipClose(zf_,"");
}

voidpf 
ZipCTL::open(const  void* filename, int  mode){
    fp_.open(( const  char*) filename, std::ios_base::binary);
   return &fp_;
}

int 
ZipCTL::close(){
    fp_.close();
   return 0;
}

ZPOS64_T 
ZipCTL::tell(){
   return fp_.tellp();
}

long 
ZipCTL::seek(ZPOS64_T  offset, int  origin){
    fp_.seekp( offset, origin);
   return 0;
}

uLong 
ZipCTL::write(const  void* buf, uLong  size){
    fp_.write((const  char*) buf, size);
   return  size;
}

void 
ZipCTL::make(const  char* root_folder, FolderList::ZIP_FLIST& mlist){
   zip_fileinfo info;
    memset(&info,0,sizeof(zip_fileinfo));
   size_t len = strlen(root_folder);

   const  int BUF = 1024;
   char in[BUF];
   size_t readsize(0);

   for( auto& item:mlist){
      SYSTEMTIME& mtime = item.time_;
       info.tmz_date.tm_hour = mtime.wHour;
       info.tmz_date.tm_mday = mtime.wDay;
       info.tmz_date.tm_min = mtime.wMinute;
       info.tmz_date.tm_mon = mtime.wMonth-1;
       info.tmz_date.tm_sec = mtime.wSecond;
       info.tmz_date.tm_year= mtime.wYear;

      const  char* m = item.filepath_.c_str();
       zipOpenNewFileInZip(zf_,m+len,&info, NULL,0,NULL,0,NULL,Z_DEFLATED, Z_BEST_SPEED);
      
       std::ifstream fp(m, std::ios_base::binary);
      do{
          fp.read(in,BUF);
          readsize = (size_t)fp.gcount();
          zipWriteInFileInZip(zf_, in,readsize);
      } while( !fp.eof() );
       fp.close();

       zipCloseFileInZip(zf_);

       std::cout<<std::endl<<m<<" Complete Compress!!";
   }

}

FolderList.h 파일
#pragma  once
#include  <Windows.h>
#include  <vector>
#include  <string>

class  FolderList
{
public:
   struct  FLIST{
       std::string filepath_;
      SYSTEMTIME   time_;
   };

   typedef std::vector<FLIST>  ZIP_FLIST;

public:
    FolderList(void);
    ~FolderList(void);

   void operator() ( std::string foldername, ZIP_FLIST& mlist);
};

FolderList.cpp 파일
#include  "FolderList.h"

FolderList::FolderList(void)
{
}

FolderList::~FolderList(void)
{
}

void 
FolderList::operator() ( std::string  foldername, ZIP_FLIST& mlist)
{
    std::string sfolder= foldername+"\\*.*";

   WIN32_FIND_DATAA ffd;
   HANDLE hFind = FindFirstFileA(sfolder.c_str(),&ffd);
   if( INVALID_HANDLE_VALUE == hFind) return;

   FLIST flist;
   FILETIME ltime;

   do{
      if( !_strcmpi(ffd.cFileName, ".") || !_strcmpi(ffd.cFileName, "..") ) continue;

       flist.filepath_ = foldername+"\\"+ffd.cFileName;
      if( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
         operator() ( flist.filepath_,mlist);
         continue;
      }
       FileTimeToLocalFileTime(&ffd.ftCreationTime,<ime);
       FileTimeToSystemTime(<ime,&flist.time_);
      mlist.push_back(flist);

   } while( FindNextFileA(hFind,&ffd));

}

ZIO_zip.cpp 파일
// ZIO_zip.cpp : Defines the entry point for the console application.
//

#include  "stdafx.h"

#include  "ZipCTL.h"


int  _tmain(int  argc, _TCHAR* argv[])
{
   FolderList::ZIP_FLIST flist;
   FolderList fn;
    fn("C:\\NVIDIA", flist);

   ZipCTL ctl("iobase.zip");

    ctl.make("C:\\NVIDIA", flist);

   return 0;
}

- 목록:

13 thoughts on “gz 파일 사용하기

  1. 안녕하세요 좋은 영상과 글을 잘 봤습니다.
    글에 보면 “입력 버퍼와 출력 버퍼를 고정으로한 압축 함수”에 대해서 어떤 함수를 봐야 하는지 알수 있을까요?
    좋은 글 감사드리며, 오래된 글에 문의를 남깁니다.
    감사합니다.

  2. 동영상 잘 보았습니다. 궁금한것이 있는데요, Z_SYNC_FLUSH 를 사용할 경우에, 만약 next_out buffer 크기가 압축한 data 를 담기에 충분하지 않는다면, 어떻게 해야 하는지요?

    • Z_SYNC_FLUSH는 쓰고 있는 비트를 모두 바이트 단위로 쓰라는 옵션임으로 일반적인 쓰기 과정에서 발생한 에러 코드를 반환하게 되어 있습니다. [Deflate 샘플] 동영상을 참고하세요.

  3. C로 압축하고 c#으로 압축을 푸는 방법이 있을까요?
    텍스트 파일을 작성시

    gzwritre(파일 포인터, 2019, sizeof(int));
    gzwritre(파일 포인터, 09, sizeof(int));
    gzwritre(파일 포인터, 17, sizeof(int));

    gzwritre(파일 포인터, 0.1, sizeof(float)); 결과값
    gzwritre(파일 포인터, 0.2, sizeof(float));
    gzwritre(파일 포인터, 0.3, sizeof(float));

    gzwritre(파일 포인터, 100.0, sizeof(float));

    이렇게 텍스트 파일을 저장(압축)했는데 C#에서 이 파일을 읽어서

    연 / 월 / 일 을 정수 변수에
    결과값을 실수배열에 저장하고 싶습니다.

  4. 분할 압축파일일 경우 zilb로 압축 해제가 가능 한가요?
    아니면 다른 라이브러리를 사용해야 할까요 ?

    • 별도로 지원하는 함수는 없지만 그냥 저장하는 과정에서 파일만 나눠 저장하는 것이 아닐지요.

  5. 안녕하세요
    c++에서 zlib uncompress로 .emf image 파일을 압축해제 하려고 합니다.
    그런데 손상된 파일이을 대상으로 진행할 경우 Z_DATA_ERROR을 반환하면서 자동종료됩니다.
    압축된 파일이 Z_DATA_ERROR를 반환하면(손상된 파일이면) 빈 .emf image 파일로 압축해제 되도록 하려면 어떻게 해야할까요?

  6. 리눅스에서 C언어를 사용해서 zlib으로 위와 같이 폴더(디렉토리)를 압축할수있나요?

Leave a Reply to hinata Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>