이번 글에서는 데이터를 압축하는 Windows API를 알아보겠습니다.
Compress를 사용하려면 아래 헤더파일과 라이브러리를 추가해야합니다.
#include "compressapi.h"
#pragma comment ( lib, "Cabinet.lib" )
압축을 위해선 우선 핸들을 만들어야 합니다.
COMPRESSOR_HANDLE hCompressor;
unsigned long ulCompSize = 0;
// 압축 핸들 만들기
if ( CreateCompressor( COMPRESS_ALGORITHM_LZMS , NULL, &hCompressor ) )
{
}
만들어진 핸들을 이용하여 우선 압축 사이즈를 구합니다.
// 압축을 위한 데이터 크기 받기
if ( FALSE == Compress( hCompressor, pOrigin, DATA_SIZE, NULL, 0, &ulCompSize ) )
{
if ( ulCompSize > 0 )
{
}
}
사이즈가 정상적으로 반환이 되면 실제 압축을 진행합니다.
unsigned char *pucTemp = new unsigned char[ulCompSize];
// 데이터를 압축 하고, 압축된 데이터의 크기를 다시 받아온다.
if ( TRUE == Compress( hCompressor, pOrigin, DATA_SIZE, pucTemp, ulCompSize, &ulCompSize ) )
{
pucComp = new unsigned char[ulCompSize];
memcpy( pucComp, pucTemp, ulCompSize );
TRACE( _T( "ulCompSize : %d\n" ), ulCompSize );
}
delete pucTemp;
압축이 모두 정상적으로 실행되면 핸들을 닫아줍니다.
CloseCompressor( hCompressor );
위 과정을 진행하면 pucComp 변수에 압축된 데이터가 있습니다.
이제 반대 과정인 압축 해제 함수를 알아보겠습니다.
압축과 비슷하게 우선 핸들부터 만들어야 합니다.
DECOMPRESSOR_HANDLE hDecompressor;
unsigned long ulDecompSize = 0;
// 압축 해제 핸들 얻기
if (CreateDecompressor( COMPRESS_ALGORITHM_LZMS, NULL, &hDecompressor ))
{
}
그 다음 압축된 데이터를 해제했을 때 데이터의 크기를 받아오는 작업을 합니다.
// 압축 해제 크기를 얻어온다.
if (FALSE == Decompress( hDecompressor, pucComp, ulCompSize, NULL, 0, &ulDecompSize ))
{
if (0 < ulDecompSize)
{
}
}
데이터 크기를 받아왔다면 그 다음엔 압축 해제를 진행합니다.
unsigned char *pucDecomp = new unsigned char[ulDecompSize];
// 압축 해제한다.
if (TRUE == Decompress( hDecompressor, pucComp, ulCompSize, pucDecomp, ulDecompSize, &ulDecompSize ))
{
TRACE( _T( "ulDecompSize : %d\n" ), ulDecompSize );
}
delete pucDecomp;
정상적으로 압축 해제를 진행했다면 핸들을 닫아줍니다.
CloseDecompressor( hDecompressor );
전체 코드는 아래와 같습니다.
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
ULONGLONG ullStart = ::GetTickCount64();
// 압축된 데이터 버퍼
unsigned char *pucComp = NULL;
// 기존 데이터 버퍼
unsigned char *pOrigin = new unsigned char[DATA_SIZE];
for ( int i = 0 ; i < DATA_SIZE ; i++ )
pOrigin[i] = i % 255;
COMPRESSOR_HANDLE hCompressor;
unsigned long ulCompSize = 0;
// 압축 핸들 만들기
if ( CreateCompressor( COMPRESS_ALGORITHM_LZMS , NULL, &hCompressor ) )
{
// 압축을 위한 데이터 크기 받기
if ( FALSE == Compress( hCompressor, pOrigin, DATA_SIZE, NULL, 0, &ulCompSize ) )
{
if ( ulCompSize > 0 )
{
unsigned char *pucTemp = new unsigned char[ulCompSize];
// 데이터를 압축 하고, 압축된 데이터의 크기를 다시 받아온다.
if ( TRUE == Compress( hCompressor, pOrigin, DATA_SIZE, pucTemp, ulCompSize, &ulCompSize ) )
{
pucComp = new unsigned char[ulCompSize];
memcpy( pucComp, pucTemp, ulCompSize );
TRACE( _T( "ulCompSize : %d\n" ), ulCompSize );
}
delete pucTemp;
}
}
CloseCompressor( hCompressor );
}
delete pOrigin;
pOrigin = NULL;
ULONGLONG ullEnd = ::GetTickCount64();
TRACE( _T( "Comp Time Gap : %d\n" ), ullEnd - ullStart );
ullStart = ::GetTickCount64();
if (NULL != pucComp)
{
DECOMPRESSOR_HANDLE hDecompressor;
unsigned long ulDecompSize = 0;
// 압축 해제 핸들 얻기
if (CreateDecompressor( COMPRESS_ALGORITHM_LZMS, NULL, &hDecompressor ))
{
// 압축 해제 크기를 얻어온다.
if (FALSE == Decompress( hDecompressor, pucComp, ulCompSize, NULL, 0, &ulDecompSize ))
{
if (0 < ulDecompSize)
{
unsigned char *pucDecomp = new unsigned char[ulDecompSize];
// 압축 해제한다.
if (TRUE == Decompress( hDecompressor, pucComp, ulCompSize, pucDecomp, ulDecompSize, &ulDecompSize ))
{
TRACE( _T( "ulDecompSize : %d\n" ), ulDecompSize );
}
delete pucDecomp;
}
}
CloseDecompressor( hDecompressor );
}
}
ullEnd = ::GetTickCount64();
TRACE( _T( "Decomp Time Gap : %d\n" ), ullEnd - ullStart );
if (NULL != pucComp)
delete pucComp;
위 소스를 보시면 16,384 크기가 44까지 줄은 것을 알 수 있습니다.
압축 옵션은 아래와 같이 4개가 있는데 각각의 옵션은 압축률과 압축시간과 관련된 옵션입니다.
COMPRESS_ALGORITHM_MSZIP // 압축률 낮고, 시간 빠름
COMPRESS_ALGORITHM_XPRESS
COMPRESS_ALGORITHM_XPRESS_HUFF
COMPRESS_ALGORITHM_LZMS // 압축률 높고, 시간 느림