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

📄 rlezip.cpp

📁 C++编的用rle编码压缩文件的程序
💻 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 + -