⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rlezip.cpp

📁 效率较高
💻 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 + -