您的位置:首页 > 其它

目录的打包和解包

2006-06-29 16:06 148 查看
由于程序中需要把整个目录打包,所以自己写了打包和解包函数,我对此打包文件的布局设计如下:
20字节:表明目录结构的起点

……

目录结构起点(前20个字节标明的):

文件内容起点:

文件FD结构

文件FD结构

文件内容

文件内容

目录FD结构

目录FD结构

目录FD结构

……

20字节:表明目录结构的起点

……

目录结构起点(前20个字节标明的):

文件内容起点:

文件FD结构

文件FD结构

文件内容

文件内容

目录FD结构

目录FD结构

目录FD结构

……

上述的FD结构其实就是:
typedef struct stFD
{
TCHAR szName[MAX_PATH]; // 文件或者目录名
long nSize; // 文件内容的大小,以字节表示,如果是目录大小为0
FILETIME cTime; // 创建时间
FILETIME aTime; // 最后访问时间
FILETIME mTime; // 最后改写时间
DWORD attribute; // 表明文件的状态
}FD;

打包函数:

void PackDir(LPCTSTR lpszDir, LPCTSTR lpszOutputFile)
{// 给出一个目录,把这个目录打包
// Param:
// lpszDir: 打包目录
// lpszOutputFile: 打包后的输出文件名

const int nOffset = 20;
CFileFind finder;
CStringList strLst;
FD fdTmp;
CFileStatus fileStatus;
CString strTmp;
BOOL bWorking;
CString strDir(_T(""));
TCHAR *pszFileContent = NULL;
CFile fileTmp;
CString strFileDirTmp;
TCHAR szCnt[nOffset];
vector<FD> vDirFD;

if(!finder.FindFile(lpszDir))
{
AfxMessageBox("目录不存在");
return;
}

// 创建打包文件
CFile PackFile;
if(!PackFile.Open(lpszOutputFile, CFile::modeCreate|CFile::modeReadWrite, NULL))
{
AfxMessageBox("创建打包文件出错!");
return;
}

// 先把文件开始的nOffset个字节占住,用于表示到目录结构所要偏移的字节数
PackFile.SeekToBegin();
PackFile.Write(szCnt, nOffset);

strLst.AddTail(lpszDir);

while(!strLst.IsEmpty())
{
strTmp = strLst.GetHead() + _T("//*.*");
bWorking = finder.FindFile(strTmp);
if(bWorking)
{
while(bWorking)
{
bWorking = finder.FindNextFile();

if(finder.IsDots())
continue;

finder.GetLastAccessTime(&fdTmp.aTime);
finder.GetCreationTime(&fdTmp.cTime);
finder.GetLastWriteTime(&fdTmp.mTime);

strFileDirTmp = finder.GetFilePath();
strFileDirTmp = strFileDirTmp.Right(strFileDirTmp.GetLength() - lstrlen(lpszDir));
lstrcpy(fdTmp.szName, strFileDirTmp);

fdTmp.nSize = finder.GetLength();
fdTmp.attribute = GetFileAttributes(finder.GetFilePath());

// 目录
if(finder.IsDirectory())
{
// 保存下来,在后面再写进文件里
vDirFD.push_back(fdTmp);

strLst.AddTail(finder.GetFilePath());
continue;
}

// 找到文件
PackFile.SeekToEnd();

// 将文件结构写进
PackFile.Write(&fdTmp, sizeof(FD));
// 将文件内容写进
pszFileContent = new TCHAR[finder.GetLength()];

if(!fileTmp.Open(finder.GetFilePath(), CFile::modeRead, NULL))
{
CString strErr;
strErr.Format("写进打包文件时,打开文件%s出错!", finder.GetFilePath());
AfxMessageBox(strErr);
return;
}
fileTmp.Read(pszFileContent, finder.GetLength());
PackFile.Write(pszFileContent, finder.GetLength());

delete pszFileContent;
}
}

strLst.RemoveHead();
}

// 在开始的nOffset个字节处写进目录结构偏移量
DWORD dwCnt = PackFile.SeekToEnd();
sprintf(szCnt, "%ld", dwCnt);
PackFile.SeekToBegin();
PackFile.Write(szCnt, nOffset);

// 去到最后写进目录结构
PackFile.SeekToEnd();
for(int i = 0; i < vDirFD.size(); i++)
{
fdTmp = vDirFD[i];
PackFile.Write(&fdTmp, sizeof(fdTmp));
}

PackFile.Close();
}

解包函数:

void UnPackDir(LPCTSTR lpszInputFile, LPCTSTR lpszDir)
{// 给出一个文件,把这个文件还原为目录
// Param:
// lpszInputFile: 利用PackDir函数打包成的文件
// lpszDir: 还原到的目录路径

const int nOffset = 20;
TCHAR szCnt[nOffset];
long nOff = 0;
CString strDir;
CString strFile;
FD fdTmp;
DWORD dwCurPos = 0;
TCHAR *pszFileContent;

CFile fileInput;
if(!fileInput.Open(lpszInputFile, CFile::modeRead, NULL))
{
AfxMessageBox("打开输入文件出错!");
return;
}

// 先建立目录结构
memset(szCnt, 0, nOffset);
fileInput.Read(szCnt, nOffset);
nOff = atoi(szCnt);
// 去到文件目录结构的起点
fileInput.Seek( nOff, CFile::begin );
while(!IsFileEnd(fileInput))
{
fileInput.Read(&fdTmp, sizeof(FD));
strDir = lpszDir;
strDir += fdTmp.szName;

CreateDirectory(strDir, NULL);

SetFileAttributes(strDir, fdTmp.attribute);
}

// 再把文件创建好
dwCurPos = fileInput.Seek(nOffset, CFile::begin);
CFile fileTmp;
while(dwCurPos < nOff)
{
fileInput.Read(&fdTmp, sizeof(FD));
strFile = lpszDir;
strFile += fdTmp.szName;

if(!fileTmp.Open(strFile, CFile::modeCreate | CFile::modeReadWrite, NULL))
{
CString strErr;
strErr.Format("解包时创建文件%s出错!", strFile);
AfxMessageBox(strErr);
return;
}
// 把内容复制过去
pszFileContent = new TCHAR[fdTmp.nSize];
fileInput.Read(pszFileContent, fdTmp.nSize);
fileTmp.SeekToBegin();
fileTmp.Write(pszFileContent, fdTmp.nSize);
delete pszFileContent;

// 把文件的属性改变,先关闭再改
fileTmp.Close();

CFileStatus rStatus;
CTime cTime(fdTmp.cTime);
CTime aTime(fdTmp.aTime);
CTime mTime(fdTmp.mTime);
rStatus.m_atime = aTime;
rStatus.m_ctime = cTime;
rStatus.m_mtime = mTime;
rStatus.m_attribute = (BYTE)fdTmp.attribute;
rStatus.m_size = fdTmp.nSize;
lstrcpy(rStatus.m_szFullName, strFile);

CFile::SetStatus(strFile, rStatus);

dwCurPos = fileInput.GetPosition();
}

fileInput.Close();
}

还有一个判断是否到了文件末尾的函数:

BOOL IsFileEnd(CFile &file)
{
DWORD dwFileLength = file.GetLength();
DWORD dwFileCurPos = file.GetPosition();

if(dwFileCurPos < dwFileLength)
{
return FALSE;
}

return TRUE;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: