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

📄 combinefiles.cpp

📁 Visual C++ 入门、进阶、与应用 如何使用合成分件文件实例 可学习操作分解文件
💻 CPP
字号:
// CombineFiles.cpp: implementation of the CCombineFiles class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Ex070203a.h"
#include "CombineFiles.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////


//CFileInfo类
CString CFileInfo::GetFileName()
{//去掉路径
	CString strFileName = m_strPathFileName ;
	for( int nPos = strFileName.GetLength() - 1 ; nPos >= 0 ; nPos-- )
	{
		char ch = strFileName[nPos] ;
		if('\\' == ch || ':' == ch || '/' == ch )
			break;				
	}
	if( -1 != nPos )
		strFileName = strFileName.Mid(nPos+1);
	
	return strFileName ;
}

int CFileInfo::Read(LPBYTE lpBuff)
{	
	m_nPosOfCombineFile = *(ULONG*)lpBuff ;
	m_nFileSize			= *(ULONG*)(lpBuff + sizeof(ULONG));
	const int nFileNameLeng	= *(ULONG*)(lpBuff + sizeof(ULONG)*2);
	char szTemp[MAX_PATH ] = {0};
	memcpy(szTemp,lpBuff + sizeof(ULONG)*3,nFileNameLeng);
	m_strPathFileName = szTemp ;
	
	return GetLeng();
}

int CFileInfo::Write(LPBYTE lpBuff)
{	
	CString strFileName = GetFileName() ;
	int nFileNameLeng = strFileName.GetLength() ;
	
	memcpy(lpBuff,&m_nPosOfCombineFile,sizeof(ULONG));
	memcpy(lpBuff + sizeof(ULONG),&m_nFileSize,sizeof(ULONG));
	memcpy(lpBuff + sizeof(ULONG)*2,&nFileNameLeng,sizeof(ULONG));
	memcpy(lpBuff + sizeof(ULONG)*3,(LPCTSTR)strFileName,nFileNameLeng);
	
	return GetLeng();
}

int CFileInfo::GetLeng()
{
	CString strFileName = GetFileName() ;
	int nLeng = sizeof(ULONG)*3 + strFileName.GetLength() ;
	return nLeng ;
}

CCombineFiles::CCombineFiles()
{

}

CCombineFiles::~CCombineFiles()
{

}

bool CCombineFiles::InitFileInfo(FILE_INFO_ARRAY& arDataFiles,const CStringArray& arStrPathFileName)
{
	for(int i = arStrPathFileName.GetSize() - 1 ; i >= 0  ; i-- )
	{
		CString		strFileName = arStrPathFileName[i] ;
		if(strFileName.IsEmpty())
			continue ;
		CFileStatus rStatus ;
		CFile::GetStatus(strFileName,rStatus);
		//取得文件长度
		CFileInfo fileInfo ;
		fileInfo.m_strPathFileName = strFileName ;
		fileInfo.m_nFileSize = rStatus.m_size ;
		//加进数组
		arDataFiles.Add(fileInfo);
	}
	return true ;
}

//CCombineFiles类

//strCombineFileName 打包后的文件名
//arStrPathFileName  数据文件名
//strExeFile         可执行文件名,打包时会放到最前面,这样此程序才可以执行
bool CCombineFiles::Combine(CString strCombineFileName,const CStringArray& arStrPathFileName,CString strExeFile )
{
	FILE_INFO_ARRAY arDataFiles ;
	InitFileInfo(arDataFiles,arStrPathFileName);
	
	ULONG nTotalSize = 0 ;
	ULONG uFileInfoPos = 0 ;
	ULONG uFileNum	   = arDataFiles.GetSize() ;
	
	//文件信息概要占用的长度
	nTotalSize += (sizeof(uFileInfoPos) + sizeof(uFileNum)) ;
	
	//文件信息占用的长度
	for(int i = arDataFiles.GetSize() - 1 ; i >= 0  ; i-- )
	{
		nTotalSize += arDataFiles[i].GetLeng() ;
	}

	//计算各文件的长度
	if(!strExeFile.IsEmpty())
	{
		CFileStatus rStatus ;
		CFile::GetStatus(strExeFile,rStatus);
		nTotalSize += rStatus.m_size ;
	}
	for(i = arDataFiles.GetSize() - 1 ; i >= 0  ; i-- )
	{
		nTotalSize += arDataFiles[i].m_nFileSize ;
	}

	HANDLE hFile = NULL ;
	HANDLE hFileMapping = NULL;
	PBYTE pbFile = NULL ;
	bool   bSuc = true ;
	ULONG nPos = 0 ;
	
	hFile = CreateFile(strCombineFileName, 
		GENERIC_READ | GENERIC_WRITE, 
		FILE_SHARE_READ, 
		NULL, 
		CREATE_ALWAYS, 
		FILE_ATTRIBUTE_NORMAL, 
		NULL); 	
	if( INVALID_HANDLE_VALUE == hFile )
	{
		bSuc = false ;
		goto End ;
	}

	hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READWRITE, 
		0, nTotalSize , NULL); 
	if( NULL == hFileMapping )
	{
		bSuc = false ;
		goto End ;
	}

	pbFile = (PBYTE)MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0,0, nTotalSize);
	if( NULL == pbFile )
	{
		bSuc = false ;
		goto End ;
	}	

	//复制Exe数据
	{
		if(!strExeFile.IsEmpty())
		{
			CFile file ;
			file.Open(strExeFile , CFile::modeRead);
			int  nFileLeng = file.GetLength() ;
			file.Read(pbFile+nPos,nFileLeng);
			nPos += nFileLeng ;
			file.Close();
		}
	}
	//复制其他文件数据
	for(i = arDataFiles.GetSize() - 1 ; i >= 0  ; i-- )
	{
		arDataFiles[i].m_nPosOfCombineFile = nPos ;
		CFile file ;
		file.Open(arDataFiles[i].m_strPathFileName , CFile::modeRead);
		file.Read(pbFile+nPos,arDataFiles[i].m_nFileSize);
		nPos += arDataFiles[i].m_nFileSize ;
		file.Close();
	}

	uFileInfoPos = nPos ;
	//写文件信息
	for(i = arDataFiles.GetSize() - 1 ; i >= 0  ; i-- )
	{
		nPos += arDataFiles[i].Write(pbFile+nPos);
	}
	//写文件概要信息
	memcpy(pbFile+nPos,&uFileNum,sizeof(ULONG));
	nPos += sizeof(ULONG);
	memcpy(pbFile+nPos,&uFileInfoPos,sizeof(ULONG));

End :
	if( NULL != pbFile )
		UnmapViewOfFile(pbFile);
	if( NULL != hFileMapping )
		CloseHandle(hFileMapping);
	if( INVALID_HANDLE_VALUE != hFile)
		CloseHandle(hFile); 

	return bSuc ;
}

//strCombineFileName 打包后的文件名
//arStrPathFileName  包含数据文件的文件夹
//strExeFile         可执行文件名,打包时会放到最前面,这样此程序才可以执行
bool CCombineFiles::Combine(CString strCombineFileName,CString strPathName,CString strExeFile )
{
	CStringArray	arFileNames ;
	if(!GetFiles(arFileNames,strPathName))
		return false ;

	return Combine(strCombineFileName,arFileNames,strExeFile);
}

//strCombineFileName 要解压的文件名
//strOutDir	解压的目录
bool CCombineFiles::Extract(CString strCombineFileName,CString strOutDir)
{
	if(strOutDir.IsEmpty())
		return false;
	if('\\' != strOutDir.Right(1) )
		strOutDir += '\\' ;

	int i = 0 ;	
	FILE_INFO_ARRAY arDataFiles ;//记录要解压后的文件的信息

	CFileStatus rStatus ;
	CFile::GetStatus(strCombineFileName,rStatus);
	ULONG nTotalSize = rStatus.m_size ;
	ULONG uFileInfoPos = 0 ;
	ULONG uFileNum	   = 0 ;

	HANDLE hFile = NULL ;
	HANDLE hFileMapping = NULL;
	PBYTE pbFile = NULL ;
	bool   bSuc = true ;
	ULONG nPos = 0 ;
	
	hFile = CreateFile(strCombineFileName, 
		GENERIC_READ , 
		FILE_SHARE_READ, 
		NULL, 
		OPEN_EXISTING, 
		FILE_ATTRIBUTE_NORMAL, 
		NULL); 	
	if( INVALID_HANDLE_VALUE == hFile )
	{
		bSuc = false ;
		goto End ;
	}
	hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READONLY, 
		0, nTotalSize , NULL); 
	if( NULL == hFileMapping )
	{
		bSuc = false ;
		goto End ;
	}
	pbFile = (PBYTE)MapViewOfFile(hFileMapping, FILE_MAP_READ, 0,0, nTotalSize);
	if( NULL == pbFile )
	{
		bSuc = false ;
		goto End ;
	}	
	//读取文件概要信息
	uFileNum = *(ULONG*)(pbFile + nTotalSize - sizeof(uFileNum) - sizeof(uFileInfoPos));
	uFileInfoPos = *(ULONG*)(pbFile + nTotalSize - sizeof(uFileNum) );

	//读取文件信息
	arDataFiles.RemoveAll();	
	for( i = 0 ; i < uFileNum ; i++ )
	{
		CFileInfo fileInfo ;
		uFileInfoPos += fileInfo.Read(pbFile + uFileInfoPos);
		arDataFiles.Add(fileInfo);
	}

	for( i = 0 ; i < uFileNum ; i++ )
	{
		CFileInfo& fileInfo = arDataFiles[i] ;
		CString strPathFileName = strOutDir + fileInfo.m_strPathFileName ;
		CFile file;
		file.Open(strPathFileName,CFile::modeCreate | CFile::modeWrite);
		file.Write(pbFile + fileInfo.m_nPosOfCombineFile,fileInfo.m_nFileSize);
		file.Close();
	}	
	
End :
	if( NULL != pbFile )
		UnmapViewOfFile(pbFile);
	if( NULL != hFileMapping )
		CloseHandle(hFileMapping);
	if( INVALID_HANDLE_VALUE != hFile)
		CloseHandle(hFile); 
	
	return bSuc ;
}

bool CCombineFiles::GetFiles(CStringArray &arFileNames, CString strPathName)
{
	if(strPathName.IsEmpty())
		return false;
	if('\\' != strPathName.Right(1) )
		strPathName += '\\' ;
	
	WIN32_FIND_DATA fd;
	HANDLE hFind = ::FindFirstFile(strPathName + "*.*",&fd);	
	if (hFind != INVALID_HANDLE_VALUE)
	{		
		while (::FindNextFile(hFind,&fd))
		{
			//判断是否为目录
			if (!(fd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))
			{
				arFileNames.Add(strPathName + fd.cFileName);
			}					
		}
		::FindClose(hFind);
	}
	else
		return false ;

	return true ;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -