📄 rlezip.cpp
字号:
/*
文件打包和解包程序 by 郭 炜
本程序用法:
rlezip -e dirname filename 将文件夹 dirname 中的所有内容打包到 filename 文件里去
dirname 可以是相对路径,也可以是绝对路径
rlezip -x filename 将文件 filename里的所有内容解出来,放到当前目录下
本程序没有进行压缩
解压函数 DeCompressDir 省略
结果文件 结构如下:
每一个文件和文件夹,在结果文件中都有 一个 tagFileInfo结构与之对应。如果一个 tagFileInfo
代表一个文件,那么在该 tagFileInfo后就紧跟着该文件的内容.
//关键函数: 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; //当前正在处理的文件夹所处的层次
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; //重复次数
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) //读取第一个字节的内容,若为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)
{
//这里(应该)进行标记,就是有多个重复的东东,写两次来标记它
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)
{
//这里(应该)进行标记,就是有多个重复的东东,写两次来标记它
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 ); //当前路径设为该文件夹
WIN32_FIND_DATA stFindClientData;
HANDLE hFindClient;
//找到第一个文件夹即其自身 " . " ,不作处理
hFindClient = FindFirstFile( "*.*", &stFindClientData );
if ( hFindClient == INVALID_HANDLE_VALUE )
{
return ;
}
//找到第二个文件夹即其父文件夹 ".. " ,,不作处理
FindNextFile( hFindClient , &stFindClientData );
//上述做法不保险,可移植性差。如果在别的操作系统或新版Windows上首先找到的不再是 "." 和".."怎么办?
//循环查找其它子文件夹和文件
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
{ //是文件
g_nCurDirLayer ++;
CompressFile( stFindClientData.cFileName);
g_nCurDirLayer --;
}
}
//关闭查找句柄
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)
{
//创建文件夹
_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) //读取第一个字节的内容,若为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 )
{ //如果是要将当前目录下的所有文件压缩到一个文件里,不考虑子目录
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)
|| strcmp( stFindClientData.cFileName , argv [argc-1]) == 0
|| strcmp( stFindClientData.cFileName , "rlezip.exe") == 0 )
{
//不进行操作
}
else
{ //如果是其他文件则进行压缩
CompressFile( stFindClientData.cFileName);
}
}
FindClose( hFindClient);
}
else
{ //如果是要将一个或多个文件或文件夹压缩到一个文件里面
int here_argc = argc - 1; //记录要压缩的文件或文件夹的个数
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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -