소개

POCO Zip은 Zip 파일을 파싱과 생성을 위한 지원이 추가되었다. 다음의 기능을 제공한다:

로컬 파일들로부터 압축해제

다운로드 되는 동안 네트웍 파일들로부터 압축해제

로컬 파일로 압축하기

네트웍 목적지로 직접 압축하기

제약

POCO Zip은 DEFLATE64 알고리즘 미지원

암호화된 파일 미지원

주 클래스들

대부분의 사용자들은 압축과 해제 두가지 클래스와 함께 작업할 것이다.

압축

압축은 Zip 파일들의 생성을 간단하게 해주는 헬퍼 클래스이다. Zip 파일을 생성하는 것은 3단계 절차 중 가장 기초적이다:

압축 객체 생성하기: 압축 스트림을 명시하고 이것이 seekable 여부를 정의하라 (지역 파일들을 위해 true로 설정하고, 네트워크 파일을 위해 false로 설정)

Compress(std::ostream& out, bool seekableOut);

엔트리 추가하기: 단일 파일 또는 디렉토리 엔트리 여부

void addFile(std::istream& input, 
             const Poco::DateTime& lastModifiedAt, 
             const Poco::Path& fileName, 
             ZipCommon::CompressionMethod cm = ZipCommon::CM_DEFLATE, 
             ZipCommon::CompressionLevel cl = ZipCommon::CL_MAXIMUM);
    /// Adds a single file to the Zip File. fileName must not be a directory name.

void addFile(const Poco::Path& file, 
             const Poco::Path& fileName, 
             ZipCommon::CompressionMethod cm = ZipCommon::CM_DEFLATE, 
             ZipCommon::CompressionLevel cl = ZipCommon::CL_MAXIMUM);
    /// Adds a single file to the Zip File. fileName must not be a directory name. The file must exist physically!

void addDirectory(const Poco::Path& entryName, const Poco::DateTime& lastModifiedAt);
    /// Adds a directory entry excluding all children to the Zip file, entryName must not be empty.

void addRecursive(const Poco::Path& entry, 
                  ZipCommon::CompressionLevel cl = ZipCommon::CL_MAXIMUM, 
                  bool excludeRoot = true, 
                  const Poco::Path& name = Poco::Path());
    /// Adds a directory entry recursively to the zip file, set excludeRoot to false to exclude the parent directory.
    /// The name specifies under which path the entries are added in the Zip file.

하나는 파일 엔트리를 추가할 때 이름을 항상 정의해야 하는 점을 알아두자. 그렇지 않으면, 압축기는 파일이 절대 또는 상대 경로로 추가되어야 할지 결정할 수가 없다. zip에 두번 파일 c:\data\hello.txt를 추가하는 것을 가정하라(?) :

// MUST use binary!
std::ofstream out("test.zip", std::ios::binary);
Compress c(out, true);
Poco::Path aFile("c:\\data\\hello.txt");
c.addFile(theFile, "hello.txt");
c.addFile(theFile, theFile);
c.close(); // MUST be done to finalize the Zip file

Zip 파일은 내부적으로 UNIX 경로 스타일로 엔트리들을 저장한다. 위에 생성된 Zip 파일은 다음의 엔트리들을 포함할 것이다.

hello.txt
data/
data/hello.txt

디렉토리 엔트리 data/는 자동적으로 추가되었다.

디렉토리를 재귀적으로 추가할 때, 같은 원리가 적용된다. 추가되어야할 루트 디렉토리와 엔트리가 Zip 파일로 추가될 부수적인 경로 명을 명시한다. 다음의 디렉토리 구조를 가정하자:

data/
   run1/
       result1.txt
   run2/
       result2.txt

다음의 호출은 Zip으로 모든 서브디렉토리와 데이터의 모든 파일들 추가될 것이지만, 루트 엔트리 데이터는 아니다:

Poco::Path data("data");
data.makeDirectory();
c.addRecursive(data);

또는 만약 디렉토리명 20070401 아래에 추가되어질 파일들을 원한다면 (기본적으로 data를 20070401로 이름 변경) :

Poco::Path data("data");
Poco::Path name("20070401);
data.makeDirectory();
name.makeDirectory();
c.addRecursive(data, ZipCommon::CL_NORMAL, false, name);

makeDirectory는 디렉토리를 만들지 않고, 간단하게 Path가 파일이 아닌 디렉토리로 다루어지는 것을 확실히 하는 것임을 알아두자. 또한 MAXIMUM(이것이 디폴트) 대신 NORMAL 압축을 사용하는 것은 개선된 성능의 잇점을 갖는다. addRecursive 동안에 추가되는 엔트리에 관한 통지를 얻기 위해서, 압축 객체의 EDone 이벤트로 등록하자(?) :

Poco::FIFOEvent<const ZipLocalFileHeader> EDone;

Zip 파일 닫기: 압축 객체를 수동으로 닫는 것은 필수이다. 이것은 유효한 Zip 파일을 생성하여, Zip 디렉토리가 만들어지는 거을 보장한다. 오직 첫번째 호출만이 효과를 얻으므로, 여러번 close를 호출하는 것은 안전하다.

ZipArchive close();

close는 모든 엔트리들이 Zip 파일 내부에 있음을 묘사해주는 ZipArchive를 리턴한다.

압축 해제

압축 해제는 Zip 파일로 부터 모든 파일들을 압축하제 하기 위해 또는 단일 파일만 해제하기 위해 사용할 수 있다.

모든 파일 압축 해제하기

다음 샘플 코드는 어떻게 모든 엔트리들이 Zip 파일로 부터 추출될 수 있는지를 보여 준다:

std::ifstream inp("test.zip", std::ios::binary);
poco_assert (inp);
// decompress to current working dir
Decompress dec(inp, Poco::Path()); 
// if an error happens invoke the ZipTest::onDecompressError method
dec.EError += Poco::Delegate<ZipTest, std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string> >(this, &ZipTest::onDecompressError);
dec.decompressAllFiles();
dec.EError -= Poco::Delegate<ZipTest, std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string> >(this, &ZipTest::onDecompressError);

onDecompressError 메소드:

void ZipTest::onDecompressError(const void* pSender, std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string>& info)
{
    // inform user about error
    [...]
}

네트워크로 부터 직접 압축해제하는 것은 유사하게 동작한다:

Poco::URI uri("http://www.appinf.com/test.zip");
HTTPClientSession session(uri.getHost(), uri.getPort());
HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
session.sendRequest(req);
HTTPResponse res;
std::istream& rs = session.receiveResponse(res);
Decompress dec(rs, Poco::Path());
// if an error happens invoke the ZipTest::onDecompressError method
dec.EError += Poco::Delegate<ZipTest, std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string> >(this, &ZipTest::onDecompressError);
dec.decompressAllFiles();
dec.EError -= Poco::Delegate<ZipTest, std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string> >(this, &ZipTest::onDecompressError);

게다가, 압축해제는 추가적인 파라미터들도 지원한다:

Decompress(std::istream& in, const Poco::Path& outputDir, bool flattenDirs = false, bool keepIncompleteFiles = false);

flattenDris이 true로 설정되어 있으면, subdirs는 추출되지 않는다. keepIncompleteFiles이 true로 설정되어 있으면, corrupt 파일들(예를 들어, 잘못된 CRC, 디스크 상의 잘못된 크기)은 삭제 될 것이다.

단일 파일들 압축해제하기

단일 파일들을 압축해제 하기 위해서, Zip 파일을 먼저 parse해야 하고, 그 다음 ZipInputStream 내부에서 투명하게 발생할 파일을 압축해제한다.

std::ifstream inp("test.zip", std::ios::binary);
poco_assert (inp);
ZipArchive arch(inp);
ZipArchive::FileHeaders::const_iterator it = arch.findHeader("data/hello.txt");
poco_assert (it != arch.headerEnd());
ZipInputStream zipin (inp, it->second);
std::ostringstream out(std::ios::binary);
Poco::StreamCopier::copyStream(zipin, out);

파일 내부에서 seek을 하는 것이 허용되는 로컬 파일들 에서만 동작할 것임을 명심하자. 네트워크 파일로 부터 직접 단일 엔트리들로 추출하는 것은 압축해제 클래스를 통해서 가능하지 않다.

results matching ""

    No results matching ""