?? rlezip.cpp
字號:
/*
文件打包和解包程序 by 郭 煒
本程序用法:
rlezip -e dirname filename 將文件夾 dirname 中的所有內(nèi)容打包到 filename 文件里去
dirname 可以是相對路徑,也可以是絕對路徑
rlezip -x filename 將文件 filename里的所有內(nèi)容解出來,放到當(dāng)前目錄下
本程序沒有進(jìn)行壓縮
解壓函數(shù) DeCompressDir 省略
結(jié)果文件 結(jié)構(gòu)如下:
每一個文件和文件夾,在結(jié)果文件中都有 一個 tagFileInfo結(jié)構(gòu)與之對應(yīng)。如果一個 tagFileInfo
代表一個文件,那么在該 tagFileInfo后就緊跟著該文件的內(nèi)容.
//關(guān)鍵函數(shù): FindFirstFile, FindNextFile , _chdir, _mkdir
*/
#include <iostream.h>
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <direct.h>
#include <io.h>
int g_nCurDirLayer = 0; //當(dāng)前正在處理的文件夾所處的層次
const int ATTR_FILE = 0;
const int ATTR_DIR = 1;
const int MAX_LENGTH = 256;
FILE * g_fpData;
int Is_Dir( char * name)
{
FILE * fp = fopen (name , "r" );
if ( fp == NULL )
{
if ( _chdir( name ) == 0 )
{
cout << name << "是文件夾" << endl;
return 1; //是文件夾
}
else
{
cout << name << "兩者都不是" << endl;
return -1; //兩者都不是
}
}
else
{
fclose(fp);
cout << name << "是文件" << endl;
return 0; //是文件
}
}
struct tagFileInfo
{
char szFileName[256]; //文件名或文件夾名字
int nLayer; //文件或文件夾所在的層次,根文件夾所處層次為0
int nLength; //文件壓縮后的長度
int nAttr; //為 ATTR_FILE 代表文件,為 ATTR_FILE 代表文件夾
};
void CompressFile( char * szFile)
{
cout << "Compressing file " << szFile << " ……" << endl;
tagFileInfo FileInfo;
FILE * fpSrc;
int c;
int i = 0;
unsigned char cCount = 0; //重復(fù)次數(shù)
long lOffsetFront = 0, lOffsetEnd; //偏移量
int nTemp;
memset( & FileInfo,0,sizeof(FileInfo));
strcpy( FileInfo.szFileName,szFile);
FileInfo.nLayer = g_nCurDirLayer;
FileInfo.nAttr = ATTR_FILE;
if ((fpSrc = fopen( szFile,"rb")) == NULL)
{
cout << "Error, failed to open file " << szFile << endl;
exit(0);
}
FileInfo.nLength = 0;
lOffsetFront = ftell(g_fpData);
fwrite( & FileInfo,1,sizeof( FileInfo),g_fpData);
if ((nTemp = fgetc(fpSrc)) == EOF) //讀取第一個字節(jié)的內(nèi)容,若為EOF則返回
{
fclose( fpSrc);
return;
}
else
fseek(fpSrc, 0, SEEK_SET); //定位回文件開頭
cCount = 0;
while(( c = fgetc( fpSrc)) != EOF)
{
if (nTemp == c && cCount < 255)
{
cCount++;
}
else
{
if (cCount > 1)
{
//這里(應(yīng)該)進(jìn)行標(biāo)記,就是有多個重復(fù)的東東,寫兩次來標(biāo)記它
for (i = 0; i < 2; i++)
{
FileInfo.nLength++;
fputc(nTemp, g_fpData);
}
FileInfo.nLength++;
fputc(cCount, g_fpData);
}
else if (cCount == 1)
{
FileInfo.nLength++;
fputc(nTemp, g_fpData);
}
nTemp = c;
cCount = 1;
}
}
if (cCount > 1)
{
//這里(應(yīng)該)進(jìn)行標(biāo)記,就是有多個重復(fù)的東東,寫兩次來標(biāo)記它
for (i = 0; i < 2; i++)
{
FileInfo.nLength++;
fputc(nTemp, g_fpData);
}
FileInfo.nLength++;
fputc(cCount, g_fpData);
}
else if (cCount == 1)
{
FileInfo.nLength++;
fputc(nTemp, g_fpData);
}
//重新寫入文件信息
lOffsetEnd = ftell(g_fpData);
fseek(g_fpData, lOffsetFront, SEEK_SET);
fwrite( & FileInfo,1,sizeof( FileInfo),g_fpData);
fseek(g_fpData, lOffsetEnd, SEEK_SET);
fclose( fpSrc);
}
void CompressDir( char * szDir )
{
cout << "Compressing folder " << szDir << endl;
tagFileInfo FileInfo;
int i,nLen;
memset( & FileInfo,0,sizeof(FileInfo));
nLen = strlen( szDir);
//不需要絕對路徑, 下面4行是抽取單純的文件夾名字
for( i = nLen; szDir[i]!= '\\' && i > 0 ;i --);
if( szDir[i] == '\\')
i++;
strcpy( FileInfo.szFileName,szDir + i);
FileInfo.nLayer = g_nCurDirLayer;
FileInfo.nAttr = ATTR_DIR;
fwrite( & FileInfo,1,sizeof( FileInfo),g_fpData);
_chdir( szDir ); //當(dāng)前路徑設(shè)為該文件夾
WIN32_FIND_DATA stFindClientData;
HANDLE hFindClient;
//找到第一個文件夾即其自身 " . " ,不作處理
hFindClient = FindFirstFile( "*.*", &stFindClientData );
if ( hFindClient == INVALID_HANDLE_VALUE )
{
return ;
}
//找到第二個文件夾即其父文件夾 ".. " ,,不作處理
FindNextFile( hFindClient , &stFindClientData );
//上述做法不保險(xiǎn),可移植性差。如果在別的操作系統(tǒng)或新版Windows上首先找到的不再是 "." 和".."怎么辦?
//循環(huán)查找其它子文件夾和文件
while ( FindNextFile( hFindClient,& stFindClientData))
{
//如果是子文件夾,則遞歸調(diào)用 CompressDir 進(jìn)行打包
if(FILE_ATTRIBUTE_DIRECTORY ==
stFindClientData.dwFileAttributes)
{
g_nCurDirLayer ++; //stFindClientData.cFileName 文件夾的層次比當(dāng)前文件夾即 szDir 多1
CompressDir( stFindClientData.cFileName);
g_nCurDirLayer --; //處理完stFindClientData.cFileName 文件夾后,層次值要恢復(fù)到 szDir 的層次值
}
else
{ //是文件
g_nCurDirLayer ++;
CompressFile( stFindClientData.cFileName);
g_nCurDirLayer --;
}
}
//關(guān)閉查找句柄
FindClose( hFindClient);
//返回父文件夾
_chdir( ".." );
}
void DeCompressDir( char * szZippedFile)
{
FILE *fpZip;
FILE *fpUnZip;
int i = 0;
int nGet, nTemp;
int nCount = 0;
tagFileInfo FileInfo;
if ((fpZip = fopen(szZippedFile, "rb")) == NULL)
{
cout << "Error, failed to open file " << szZippedFile << endl;
exit(0);
}
g_nCurDirLayer = 0;
while (fread( &FileInfo, 1, sizeof(FileInfo), fpZip) == sizeof(FileInfo))
{
if (FileInfo.nAttr == ATTR_DIR)
{ //如果是文件夾
if (g_nCurDirLayer == FileInfo.nLayer)
{
//創(chuàng)建文件夾
_mkdir(FileInfo.szFileName);
g_nCurDirLayer++;
_chdir(FileInfo.szFileName);
}
else if (g_nCurDirLayer > FileInfo.nLayer)
{ //不相等,空文件夾,退回上層
for (i = 0; i < (g_nCurDirLayer - FileInfo.nLayer); i++)
_chdir("..");
g_nCurDirLayer = FileInfo.nLayer;
_mkdir(FileInfo.szFileName);
g_nCurDirLayer++;
_chdir(FileInfo.szFileName);
}
}
else
{ //如果是文件
cout << "Decompressing file " << FileInfo.szFileName << "……" << endl;
if (g_nCurDirLayer > FileInfo.nLayer)
{ //不相等,空文件夾,退回上層
for (i = 0; i < (g_nCurDirLayer - FileInfo.nLayer); i++)
_chdir("..");
g_nCurDirLayer = FileInfo.nLayer;
}
if ( (fpUnZip = fopen(FileInfo.szFileName, "wb")) == NULL)
{
cout << "Error, can not creat file " << FileInfo.szFileName << endl;
break;
}
if ((nTemp = fgetc(fpZip)) == EOF) //讀取第一個字節(jié)的內(nèi)容,若為EOF則退出
{
fclose( fpZip);
continue;
}
for (i = 0; i < FileInfo.nLength; )
{
nGet = fgetc(fpZip);
i++;
if (nGet == nTemp)
{
nCount = fgetc(fpZip);
i++;
if (i == FileInfo.nLength - 1)
nCount--;
for (int j = 0; j < nCount; j++)
fputc(nTemp, fpUnZip);
if (i < FileInfo.nLength -1)
{
nTemp = fgetc(fpZip);
i++;
}
}
else if (nGet != nTemp)
{
fputc(nTemp, fpUnZip);
nTemp = nGet;
}
}
cout << "Decompressing file " << FileInfo.szFileName << " Finished!" << endl;
fclose(fpUnZip);
fseek(fpZip, -1, SEEK_CUR);
}
}
fclose(fpZip);
}
void main( int argc, char * argv[])
{
if ( argc == 1 )
{
cout << "Error: No filename." << endl;
exit(0);
}
if ( stricmp( argv[1],"-e") == 0 )
{
g_fpData = fopen( argv[argc - 1], "wb");
if ( stricmp( argv[2], "*") == 0 )
{ //如果是要將當(dāng)前目錄下的所有文件壓縮到一個文件里,不考慮子目錄
WIN32_FIND_DATA stFindClientData;
HANDLE hFindClient;
hFindClient = FindFirstFile( "*.*" , &stFindClientData );
if ( hFindClient == INVALID_HANDLE_VALUE )
{
return ;
}
FindNextFile( hFindClient , & stFindClientData );
while ( FindNextFile( hFindClient,& stFindClientData))
{ //以下文件不在壓縮名單之內(nèi):壓縮目標(biāo)文件、壓縮可執(zhí)行文件
if((FILE_ATTRIBUTE_DIRECTORY ==stFindClientData.dwFileAttributes)
|| strcmp( stFindClientData.cFileName , argv [argc-1]) == 0
|| strcmp( stFindClientData.cFileName , "rlezip.exe") == 0 )
{
//不進(jìn)行操作
}
else
{ //如果是其他文件則進(jìn)行壓縮
CompressFile( stFindClientData.cFileName);
}
}
FindClose( hFindClient);
}
else
{ //如果是要將一個或多個文件或文件夾壓縮到一個文件里面
int here_argc = argc - 1; //記錄要壓縮的文件或文件夾的個數(shù)
int i;
for (i = 2; i < here_argc; i++ )
{
int IsDir = Is_Dir( argv[i] );
if (IsDir == -1) //文件或者文件夾不存在
{
cout << "Error: File or folder is not found." << endl;
fclose( g_fpData );
remove( argv[here_argc-1] );
exit(0); //退出程序
}
else if (IsDir == 1)
{
CompressDir( argv[i] );
}
else if (IsDir == 0)
{
CompressFile( argv[i] );
}
}
}
fclose( g_fpData);
}
else if ( stricmp( argv[1],"-x") ==0 )
DeCompressDir( argv[argc - 1]);
else
cout << "Error!" << endl;
cout << "Finished!" << endl;
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -