?? rlezip.cpp
字號:
#include <iostream.h>
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <direct.h>
#include <io.h>
int g_nCurDirLayer = 0; //當前正在處理的文件夾所處的層次
const int ATTR_FILE = 0;
const int ATTR_DIR = 1;
FILE * g_fpData; //壓縮時的目標文件
FILE * g_fpZippedFile; //解壓縮時的目標文件
struct tagFileInfo
{
char cFileNameLength; //文件名的長度(使寫在文件中的文件信息縮短)
char szFileName[256]; //文件名或文件夾名字
int nLayer; //文件或文件夾所在的層次,根文件夾所處層次為0
int nLength; //文件壓縮后的長度
int nAttr; //為 ATTR_FILE 代表文件,為 ATTR_FILE 代表文件夾
};
void WriteFileInfo(tagFileInfo & FileInfo)
{
//將文件信息寫入文件
int i = 0;
fwrite( & FileInfo.cFileNameLength,sizeof(char),1,g_fpData);
while( FileInfo.szFileName[i]!='\0')
fwrite( & FileInfo.szFileName[i++],sizeof(char),1,g_fpData);
fwrite( & FileInfo.nLayer,sizeof(int),1,g_fpData);
fwrite( & FileInfo.nLength,sizeof(int),1,g_fpData);
fwrite( & FileInfo.nAttr,sizeof(int),1,g_fpData);
}
void CompressFile( char * szFile)
{
//壓縮一個文件
tagFileInfo FileInfo;
FILE * fpSrc; //目標文件指針
int i,j,k;
int c;
int power; //用于計算2^n
int CompressTypt[8]; //標示(m個n,還是n)
char CompressNum[8]; //字符連續的個數
char CompressChar[8]; //字符
int nFileEnd; //在一個壓縮單元中,文件結束的位置
const int NUM_CHAR = 0;
const int ONLY_CHAR = 1;
int nCharNum = 1; //相同字符連續的個數
char cCurrentChar = -1; //紀錄上一個字符
int nTemp = 0;
//建立文件信息
memset( CompressTypt,0,sizeof(bool)*8);
memset( & FileInfo,0,sizeof(FileInfo));
strcpy( FileInfo.szFileName,szFile);
FileInfo.cFileNameLength = (char)strlen( szFile);
FileInfo.nLayer = g_nCurDirLayer;
FileInfo.nAttr = ATTR_FILE;
//計算壓縮后的文件長度
fpSrc = fopen( szFile,"rb");
if (fpSrc == NULL) //錯誤處理
{
cout<<"The file "<<szFile<<" is not exist!"<<endl;
return;
}
c = fgetc( fpSrc);
cCurrentChar = c;
nCharNum = 1;
while(1)
{
FileInfo.nLength++; //每1個壓縮單元有1字節儲存標示
i=0;
while(i<8)
{
c = fgetc( fpSrc);
if (c == cCurrentChar && nCharNum < 255)
nCharNum++;
else
{
i++;
if (nCharNum > 1)
FileInfo.nLength+=2; //m個n,要寫入m n,所以占兩字節
else
FileInfo.nLength++; //只寫入該字符,只占一字節
cCurrentChar = c;
nCharNum = 1;
}
if (c == EOF)
break; //到達文件最后,退出循環
}
if (c == EOF)
break;
}
fclose( fpSrc);
//將文件信息寫入文件
WriteFileInfo( FileInfo);
//將壓縮碼寫入文件
//重新打開文件
fpSrc = fopen( szFile,"rb");
c = fgetc( fpSrc);
cCurrentChar = c;
nCharNum = 1;
while(1)
{
memset(CompressTypt,0,8);
memset(CompressChar,0,8);
memset(CompressNum,0,8);
nFileEnd= 9;
j=0;
//儲存一個壓縮單元中的信息,并輸出至目標文件
//一個壓縮單元包括:
//表示8個標示的一個字節,下面是8個壓縮碼(m n或n的形式)
while(j<8)
{
//儲存下面8個壓縮的信息到內存(包括字符,個數,以及標示)
c = fgetc( fpSrc);
if (c == cCurrentChar && nCharNum < 255)
nCharNum++;
else
{
if (nCharNum > 1)
CompressTypt[j] = NUM_CHAR; //儲存標示
else
CompressTypt[j] = ONLY_CHAR;
CompressNum[j] = nCharNum; //儲存個數
CompressChar[j] = cCurrentChar; //儲存字符
cCurrentChar = c;
nCharNum = 1;
j++;
}
if (j == 8)
break; //一個單元結束,退出循環
if (c == EOF)
{
nFileEnd = j;
break; //文件結束,退出循環
}
}
//將儲存好的8位標示轉換成10進制整數,并寫在一個字節中
nTemp=0;
for (j=0; j<8 && j<nFileEnd; j++)
{
power = 1;
for (k=1; k<8-j; k++)
power*= 2;
nTemp+= CompressTypt[j] * power;
}
if (nFileEnd != 0)
fputc( (char)nTemp,g_fpData);
//依次寫入8個壓縮碼
for (j=0;j<8 && j<nFileEnd;j++)
{
if (CompressTypt[j] == NUM_CHAR)
{
fputc( CompressNum[j],g_fpData);
fputc( CompressChar[j],g_fpData);
}else
fputc( CompressChar[j],g_fpData);
}
if (j == nFileEnd)
break;
}
fclose( fpSrc);
}
void DeCompressFile( tagFileInfo & FileInfo)
{
//解壓縮一個文件
FILE * fpAim;
int nNum; //8個標示對應的十進制數
int i = 0,j,k;
int nCharNum = 1; //相同字符連續的個數
int power; //用于計算2^n
char cCurrentChar = -1; //紀錄上一個字符
int CompressTypt[8]; //儲存標示
const int NUM_CHAR = 0;
const int ONLY_CHAR = 1;
fpAim = fopen( FileInfo.szFileName,"wb");
while(1)
{
//翻譯一個壓縮單元中的信息,并輸出至目標文件
//一個壓縮單元包括:
//表示8個標示的一個字節,下面是8個壓縮碼(m n或n的形式)
//讀出表示標示的一個字節,并將其轉為8位的標示
nNum = fgetc( g_fpZippedFile);
i++;
for (j=0; j<8 ; j++)
{
power = 1;
for (k=1; k<8-j; k++)
power*= 2;
CompressTypt[j] = nNum / power;
nNum-= CompressTypt[j] * power;
}
//根據標示,將下面的8個壓縮碼轉換為文件,并輸出
for (j=0;j<8;j++)
{
//如果幾個相同字符連在一起
if (CompressTypt[j] == NUM_CHAR)
{
i+=2;
nCharNum = (int)fgetc( g_fpZippedFile);
cCurrentChar = fgetc( g_fpZippedFile);
for (k=0; k<nCharNum; k++)
fputc(cCurrentChar,fpAim);
}
//如果沒有連續字符
if (CompressTypt[j] == ONLY_CHAR)
{
i++;
cCurrentChar = fgetc( g_fpZippedFile);
fputc(cCurrentChar,fpAim);
}
//到達文件最后,則退出
if (i>=FileInfo.nLength)
break;
}
if (i>=FileInfo.nLength)
break;
}
fclose( fpAim);
}
void CompressDir( char * szDir )
{
//壓縮一個文件夾
tagFileInfo FileInfo;
int i,nLen;
memset( & FileInfo,0,sizeof(FileInfo));
nLen = strlen( szDir);
//不需要絕對路徑, 下面4行是抽取單純的文件夾名字
for( i = nLen; i > 0 ;i --)
if (szDir[i]== '\\' || szDir[i]=='/')
break;
if( szDir[i] == '\\' || szDir[i]=='/')
i ++;
strcpy( FileInfo.szFileName,szDir + i);
FileInfo.cFileNameLength = strlen(FileInfo.szFileName);
FileInfo.nLayer = g_nCurDirLayer;
FileInfo.nAttr = ATTR_DIR;
WriteFileInfo(FileInfo);
g_nCurDirLayer ++;
_chdir( szDir ); //當前路徑設為該文件夾
WIN32_FIND_DATA stFindClientData;
HANDLE hFindClient;
//找到第一個文件夾即其自身 " . " ,不作處理
hFindClient = FindFirstFile( "*.*" , &stFindClientData );
if ( hFindClient == INVALID_HANDLE_VALUE )
{
return ;
}
//找到第二個文件夾即其父文件夾 ".. " ,,不作處理
FindNextFile( hFindClient , & stFindClientData );
//循環查找其它子文件夾和文件
while ( FindNextFile( hFindClient,& stFindClientData))
{
//如果是子文件夾,則遞歸調用 CompressDir 進行打包
if (FILE_ATTRIBUTE_DIRECTORY == stFindClientData.dwFileAttributes)
{
// g_nCurDirLayer ++; //stFindClientData.cFileName 文件夾的層次比當前文件夾即 szDir 多1
CompressDir( stFindClientData.cFileName);
// g_nCurDirLayer --; //處理完stFindClientData.cFileName 文件夾后,層次值要恢復到 szDir 的層次值
}
else //是文件
{
CompressFile( stFindClientData.cFileName);
}
}
//關閉查找句柄
FindClose( hFindClient);
//返回父文件夾
_chdir( ".." );
g_nCurDirLayer --;
}
void DeCompressDir()
{
//解壓縮一個文件夾
tagFileInfo FileInfo;
int nZippedFileSeek;
int i;
while(1)
{
nZippedFileSeek = ftell( g_fpZippedFile); //紀錄偏移量
//讀入文件信息
FileInfo.cFileNameLength = fgetc(g_fpZippedFile);
if (FileInfo.cFileNameLength == EOF)
break;
for (i=0; i<(int)FileInfo.cFileNameLength; i++)
FileInfo.szFileName[i] = fgetc(g_fpZippedFile);
FileInfo.szFileName[i] = '\0';
fread( & FileInfo.nLayer,sizeof(int),1,g_fpZippedFile);
fread( & FileInfo.nLength,sizeof(int),1,g_fpZippedFile);
fread( & FileInfo.nAttr,sizeof(int),1,g_fpZippedFile);
//如果該層次結束,則將文件重新定位到上面儲存的偏移量上
if (FileInfo.nLayer != g_nCurDirLayer)
{
fseek(g_fpZippedFile,nZippedFileSeek,SEEK_SET);
break;
}
if (FileInfo.nAttr == ATTR_FILE)
DeCompressFile( FileInfo); //解壓縮文件
if (FileInfo.nAttr == ATTR_DIR)
{
g_nCurDirLayer++;
_mkdir(FileInfo.szFileName); //建立文件夾
_chdir(FileInfo.szFileName); //進入該文件夾
DeCompressDir(); //解壓縮文件夾(遞歸)
g_nCurDirLayer--;
_chdir( ".." ); //返回上一級文件夾
}
}
}
void CompressCurDir(char * szName)
{
WIN32_FIND_DATA stFindClientData;
HANDLE hFindClient;
//找到第一個文件夾即其自身 " . " ,不作處理
hFindClient = FindFirstFile( "*.*" , &stFindClientData );
if ( hFindClient == INVALID_HANDLE_VALUE )
return ;
//找到第二個文件夾即其父文件夾 ".. " ,,不作處理
FindNextFile( hFindClient , & stFindClientData );
while ( FindNextFile( hFindClient,& stFindClientData))
{
if (FILE_ATTRIBUTE_DIRECTORY == stFindClientData.dwFileAttributes) {}
else{
if (strcmp(stFindClientData.cFileName,"rlezip.exe") != 0
&& strcmp(stFindClientData.cFileName,szName) != 0 )
CompressFile( stFindClientData.cFileName);
}
}
//關閉查找句柄
FindClose( hFindClient);
}
void main( int argc ,char * argv[])
{
int i,j;
int nDirLength;
int nIsFile;
if( argc == 1 )
return;
if( strcmp( argv[1],"-e") == 0 )
{
g_fpData = fopen( argv[argc-1],"wb");
for (i=2; i<argc-1; i++){ //依次處理每個待壓縮的程序
if (strcmp(argv[i],"*") == 0)
{
CompressCurDir(argv[argc-1]);
continue;
}
g_nCurDirLayer = 0;
nDirLength = strlen(argv[i]);
nIsFile = 0;
for (j=0; j<nDirLength; j++)
{
if (argv[i][j] == '.')
{
nIsFile = 1;
break;
}
}
if (nIsFile == 1)
CompressFile( argv[i]);
else
CompressDir( argv[i]);
}
fclose( g_fpData);
}
else if( stricmp( argv[1],"-x") ==0 )
{
g_nCurDirLayer = 0;
g_fpZippedFile = fopen(argv[2],"rb");
if (g_fpZippedFile != NULL) //錯誤處理
{
DeCompressDir();
fclose(g_fpZippedFile);
}else
cout<<"The file "<<argv[2]<<" is not exist!"<<endl;
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -