首先登陆7z官方组织网站https://www.7-zip.org/,英文不好的朋友可先切换至中文。
打开左边LZMA SDK页面,下载如下图最新SDK和说明文档。
下载好后,SDK包内容对多种编程语言进行了支持,这里只研究C++(即CPP),其他类似。
首先是对各种加解压缩模块的支持,对应如下目录:
关于这些模块,在lzma1900\DOC目录下的lzma-sdk.txt文件中,有如下一段说明:
Bundles - Modules that are bundles of other modules (files)
Alone7z - 7zr.exe: Standalone 7-Zip console program (reduced version)
Format7zExtractR - 7zxr.dll: Reduced version of 7z DLL: extracting from 7z/LZMA/BCJ/BCJ2.
Format7zR - 7zr.dll: Reduced version of 7z DLL: extracting/compressing to 7z/LZMA/BCJ/BCJ2
LzmaCon - lzma.exe: LZMA compression/decompression
LzmaSpec - example code for LZMA Specification
SFXCon - 7zCon.sfx: Console 7z SFX module
SFXSetup - 7zS.sfx: 7z SFX module for installers
SFXWin - 7z.sfx: GUI 7z SFX module
这里之所以提到这些模块,是因为后面我们要用到他们编译dll,来给VC调用。
如这里我们用到的是D:\7z压缩\lzma1900\CPP\7zip\Bundles\Format7zR,SDK库中已经为我们提供了对应的makefile文件。我们只需要使用不同版本的VS中提供的nmake工具,来进行编译即可。
使用如上图VS的命令工具,直接使用cd命令进到对应目录下,nmake编译即可。
编译完成后如下:
如下图目录中,新编译出的如下7zra.dll,即为我们需要的供vc调用的动态库,虽然网上也提供了很多用ShellExcute去操作7z.exe等的命令实现方式,但是为了保证主程序只有一个执行文件,这里我没有采用这种方式。
有了动态库7zra.dll,接下来我们需要参阅D:\lzma1900\CPP\7zip\UI\Client7z下的示例工程,修整出我们的vc压缩库,用VS打开如下工作空间:
原始工程即可通过编译:
但提供的main函数中涉及了很多对命令行的解析和操作,有点冗长,我对很多地方做了一些简化和调整,整理出如下的一个通用函数。此外,我们需要明白7z sdk 关于压缩这一块的基本架构,首先我们需要一个Vector向量组CObjectVector<CDirItem> &dirItems,它的每个项目其实就是用来存放我们需要压缩的某个文件的信息,它将被用于在CArchiveUpdateCallback类Init(&dirItems)时传入。此外,我们还需要一个最终压缩得到的*.7z的最终压缩文件的路径,该路径archiveName被用于在CArchiveUpdateCallback类构建时传入Create(archiveName, true)。
了解了压缩的过程,解压缩过程已经比较简单了,留给读者自行实现即可。
这里为了实现调试该项目,我们需要对该工程做如下位置的调整。
此外,别忘了把之前的库7zra.dll拷贝到生成的执行文件Client.exe目录下。
如下我对Client7z.cpp做了以下位置的一些调整,没有用到的部分直接注释和删除了。
另编写了如下的几个函数,来实现递归子级目录的压缩,简化了main函数的内容。
//封装的获取压缩文件夹列表文件函数
bool GetArchiveItemFromPath(const char * strDirPath,const char * parentDirPath,CObjectVector<CDirItem> &dirItems)
{
//注意这里提供了一个从const char * 转换到FString的函数CmdStringToFString,
//但我没有用,而是直接用的库提供的宏来做转换
NWindows::NFile::NFind::CFindFile findFile;
NWindows::NFile::NFind::CFileInfo fileInfo;
FString dirPath = fas2fs(strDirPath);
bool bRet = findFile.FindFirst(dirPath + fas2fs("\\*.*"),fileInfo);
if (bRet == false)return bRet;
do //递归遍历出所有的包含目录和文件并记录
{
if (fileInfo.IsDots())
{
continue;
}
CDirItem di;
di.Attrib = fileInfo.Attrib;
di.Size = fileInfo.Size;
di.CTime = fileInfo.CTime;
di.ATime = fileInfo.ATime;
di.MTime = fileInfo.MTime;
//一定要赋值为压缩根路径下的全路径,否则不能压缩子目录内容及递归压缩子
//目录的子目录下的内容,他们的内容将是空的
if (parentDirPath != NULL)
{
di.Name = fas2fs(parentDirPath);
di.Name += fas2fs("\\");
di.Name += fileInfo.Name;
}
else
{
di.Name = fileInfo.Name;
}
di.FullPath = dirPath;
di.FullPath+= fas2fs("\\");
di.FullPath+=fileInfo.Name;
dirItems.Add(di);
if (fileInfo.IsDir())
{
FString parentPath;
if (parentDirPath != NULL)
{
parentPath = fas2fs(parentDirPath);
parentPath += fas2fs("\\");
parentPath += fileInfo.Name;
}
else
{
parentPath = fileInfo.Name;
}
FString fFullPath = dirPath;
fFullPath+= fas2fs("\\");
fFullPath+=fileInfo.Name;
//递归所有的子级目录的内容
GetArchiveItemFromPath(fs2fas(fFullPath),fs2fas(parentPath),dirItems);
}
}while(findFile.FindNext(fileInfo));
findFile.Close();
return true;
}
DWORD ArchiveFile(CObjectVector<CDirItem> &dirItems,const char * ArchivePackPath)
{
NT_CHECK
NDLL::CLibrary lib;
//加载7zra.dll库
if (!lib.Load(NDLL::GetModuleDirPrefix() + FTEXT(kDllName)))
{
PrintError("Can not load 7-zip library");
return 1;
}
//导出CreateObject函数指针
Func_CreateObject createObjectFunc = (Func_CreateObject)lib.GetProc("CreateObject");
if (!createObjectFunc)
{
PrintError("Can not get CreateObject");
return 1;
}
FString archiveName = fas2fs(ArchivePackPath); //压缩文件路径
COutFileStream *outFileStreamSpec = new COutFileStream;
CMyComPtr<IOutStream> outFileStream = outFileStreamSpec;
if (!outFileStreamSpec->Create(archiveName, false)) //创建压缩文件
{
PrintError("can't create archive file");
return 1;
}
CMyComPtr<IOutArchive> outArchive;
//构件压缩对象
if (createObjectFunc(&CLSID_Format, &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_VECTOR (i, updateCallbackSpec->FailedFiles)
{
PrintNewLine();
PrintError("Error for file", updateCallbackSpec->FailedFiles[i]);
}
if (updateCallbackSpec->FailedFiles.Size() != 0) //判断有几个文件压缩失败
return 1;
return 0;
}
// Main function
#define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1;
int MY_CDECL main(int numArgs, const char *args[])
{
numArgs = numArgs; //纯粹消除编译警告,无任何意义
args = args;
CObjectVector<CDirItem> ItemList;
GetArchiveItemFromPath("D:\\Mycomputer\\abc",NULL,ItemList);
ArchiveFile(ItemList,"D:\\Mycomputer\\abc\\CPP.7Z");
return 0;
}
测试时我使用了如下的三级子目录结构,可以正常实现对其的压缩。
如需如下源码包研究的,可在链接中下载源码。
来源:https://blog.csdn.net/tanjiaqi2554/article/details/99472373