📄 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 + -