最近准備做一個用戶端 異常收集的程序 需要收集用戶機器的程序日志和相關信息 准備打包發回來 所以研究了一下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"); */