原文地址:http://www.cnblogs.com/FCoding/p/3531124.html
最近准备做一个用户端 异常收集的程序 需要收集用户机器的程序日志和相关信息 准备打包发回来 所以研究了一下7Z 文件压缩 做一个笔记吧
遇到的问题:
1:VS2008 遇到 loadlibrary 以后显示 ERROR 6034
解决方案
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.VC90.CRT' version='9.0.21022.8' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b'\"")
2:根据源码 没编译对正确的7z.dll
最终使用的是 7z920.tar\CPP\7zip\Bundles\Format7zF 里面编译的7z.dll
攻略:
编译DLL 的方式
由于 可以使用VS 也可以使用makefile
makefile 使用方法:1启动VS2008命令行工具 并切换到对应目录 执行 nmake 等待即可
代码demo
由于只用到压缩 就不贴解压代码了
源码自带Demo 目录 7z920.tar\CPP\7zip\UI\Client7z
源码分析:
入参:打包的文件信息列表 和目标包的 路径
复制代码
DWORD ArchiveFile(CObjectVector<CDirItem> &dirItems,LPCWSTR ArchivePackPath)
{
NT_CHECK
NWindows::NDLL::CLibrary lib;
if (!lib.Load(TEXT(kDllName)))//加载7z.dll
{
PrintError("Can not load 7-zip library");
return 1;
}
CreateObjectFunc createObjectFunc = (CreateObjectFunc)lib.GetProc("CreateObject");//获取COM 接口
if (createObjectFunc == 0)
{
PrintError("Can not get CreateObject");
return 1;
}
UString archiveName=ArchivePackPath;//打包后的位置 //保存打包位置
COutFileStream *outFileStreamSpec = new COutFileStream;
CMyComPtr<IOutStream> outFileStream = outFileStreamSpec;
if (!outFileStreamSpec->Create(archiveName, true))//创建 打包文件
{
PrintError("can't create archive file");
return 1;
}
CMyComPtr<IOutArchive> outArchive; //取IOUTARCHIVE 接口
if (createObjectFunc(&CLSID_CFormat7z, &IID_IOutArchive, (void **)&outArchive) != S_OK)
{
PrintError("Can not get class object");
return 1;
}
CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; //压缩时 会调用的回调函数
CMyComPtr<IArchiveUpdateCallback2> updateCallback(updateCallbackSpec);
updateCallbackSpec->Init(&dirItems);
HRESULT result = outArchive->UpdateItems(outFileStream, dirItems.Size(), updateCallback);
updateCallbackSpec->Finilize(); //压缩
if (result != S_OK)
{
PrintError("Update Error");
return 1;
}
for (int i = 0; i < updateCallbackSpec->FailedFiles.Size(); i++) //打印失败文件
{
PrintNewLine();
PrintString((UString)L"Error for file: " + updateCallbackSpec->FailedFiles[i]);
}
if (updateCallbackSpec->FailedFiles.Size() != 0)//判断有几个失败的文件
return 1;
return 1;
}
复制代码
打包文件的获取 我自己封装了一下 又以下2种方式
一种是 打包一个文件夹 一种是通过一个文件名全路径的list 打包
复制代码
VOID GetArchiveItemFromPath(LPCTSTR strDirPath,CObjectVector<CDirItem> &dirItems)
{
NFile::NFind::CFileInfo fi;
NFile::NFind::CFindFile TEST;
AString dirPath;
dirPath=strDirPath;
dirPath+="\\*.*";
TEST.FindFirst(dirPath,fi);
while(TEST.FindNext(fi))
{
if (fi.IsDots())
{
continue;
}
CDirItem di;
di.Attrib = fi.Attrib;
di.Size = fi.Size;
di.CTime = fi.CTime;
di.ATime = fi.ATime;
di.MTime = fi.MTime;
di.Name = MultiByteToUnicodeString(fi.Name);
di.FullPath = MultiByteToUnicodeString(strDirPath);
di.FullPath+=MultiByteToUnicodeString("\\");
di.FullPath+=MultiByteToUnicodeString(fi.Name);
dirItems.Add(di);
}
}
复制代码
复制代码
DWORD GetArchiveItemFromFileList(CObjectVector<AString> FileList,CObjectVector<CDirItem> &ItemList)
{
NFile::NFind::CFileInfo fi;
for (int i=0;i<FileList.Size();i++)
{
if (fi.Find(FileList[i]))
{
CDirItem di;
di.Attrib = fi.Attrib;
di.Size = fi.Size;
di.CTime = fi.CTime;
di.ATime = fi.ATime;
di.MTime = fi.MTime;
di.Name = MultiByteToUnicodeString(fi.Name);
di.FullPath = MultiByteToUnicodeString(FileList[i]);
ItemList.Add(di);
}
}
return 1;
}
复制代码
复制代码
//example
/*
CObjectVector<CDirItem> ItemList;
GetArchiveItemFromPath("C:\\Users\\kr\\Desktop\\VPN",ItemList);
ArchiveFile(ItemList,L"dirPath.7Z");
CObjectVector<CDirItem> ItemList;
CObjectVector<AString> fileList;
fileList.Add("C:\\Users\\kr\\Desktop\\VPN\\VPN.txt");
fileList.Add("C:\\Users\\kr\\Desktop\\VPN.txt");
fileList.Add("C:\\Users\\kr\\Desktop\\VPN\\VPN3.txt");
GetArchiveItemFromFileList(fileList,ItemList);
ArchiveFile(ItemList,L"File.7Z");
*/
复制代码