有时候我们只需要单纯对lzma算法压缩的7z文件进行解压,有时需要在嵌入式设备上解压,使用p7zip虽然支持多种格式,但是不容易裁剪,使用lzma SDK是首选:

我下载了4.65版本,这个对文件名编码支持没有9.20的好,中文可能有问题,但是我的需求不需要支持中文文件名,所以足够用了。

解压后先看一下7z这个工程,这个示例只有文件解压操作,仿照就可以写一个更加精简的解压函数:

需要的文件可以参考实例:

修改7zMain.c即可

我们的目的是写一个函数extract7z,接收参数是7z文件路径,输出文件路径,便可执行全部解压

主要调用函数:

SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp);

SRes SzAr_Extract(

const CSzArEx *p,

ILookInStream *inStream,

UInt32 fileIndex,

UInt32 *blockIndex,

Byte **outBuffer,

size_t *outBufferSize,

size_t *offset,

size_t *outSizeProcessed,

ISzAlloc *allocMain,

ISzAlloc *allocTemp);

我们先在Windows下编译:

完整代码如下:

/* 7zMain.c - Test application for 7z Decoder

2008-11-23 : Igor Pavlov : Public domain */

#include

#include

#include

#define LOGD printf

#define LOGE printf

#include "7zCrc.h"

#include "7zFile.h"

#include "7zVersion.h"

#include "7zAlloc.h"

#include "7zExtract.h"

#include "7zIn.h"

int MY_CDECL extract7z(const char* srcFile, const char* dstPath)

{

CFileInStream archiveStream;

CLookToRead lookStream;

CSzArEx db;

SRes res;

ISzAlloc allocImp;

ISzAlloc allocTempImp;

char outPath[1024] = { 0 };

LOGD("7z ANSI-C Decoder " MY_VERSION_COPYRIGHT_DATE "\n");

if (InFile_Open(&archiveStream.file, srcFile)) {//open 7z file

LOGE("can not open input file\n");

return 1;

}

FileInStream_CreateVTable(&archiveStream);

LookToRead_CreateVTable(&lookStream, False);

lookStream.realStream = &archiveStream.s;

LookToRead_Init(&lookStream);

allocImp.Alloc = SzAlloc;

allocImp.Free = SzFree;

allocTempImp.Alloc = SzAllocTemp;

allocTempImp.Free = SzFreeTemp;

CrcGenerateTable();

SzArEx_Init(&db);

res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp);

if(res == SZ_OK)

{

Int32 i;

UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */

Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */

size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */

LOGD("Total file/directory count[%d]\n", db.db.NumFiles);

for (i = db.db.NumFiles - 1; i >= 0; i--) {

size_t offset;

size_t outSizeProcessed;

CSzFileItem *f = db.db.Files + i;

strcpy(outPath, dstPath);

strcat(outPath, "/");

strcat(outPath, f->Name);

if (f->IsDir) {//dir

LOGD("dir [%s]\n", outPath);

mkdir(outPath);

continue;

}else{//file

LOGD("file [%s]\n", outPath);

res = SzAr_Extract(&db, &lookStream.s, i, &blockIndex,

&outBuffer, &outBufferSize, &offset, &outSizeProcessed,

&allocImp, &allocTempImp);

if (res != SZ_OK){

break;

}else{

CSzFile outFile;

size_t processedSize;

if (OutFile_Open(&outFile, outPath)) {

LOGE("can not open output file\n");

res = SZ_ERROR_FAIL;

break;

}

processedSize = outSizeProcessed;

if (File_Write(&outFile, outBuffer + offset, &processedSize)

!= 0 || processedSize != outSizeProcessed) {

LOGE("can not write output file\n");

res = SZ_ERROR_FAIL;

break;

}

if (File_Close(&outFile)) {

LOGE("can not close output file\n");

res = SZ_ERROR_FAIL;

break;

}

}

}

}

IAlloc_Free(&allocImp, outBuffer);

}

SzArEx_Free(&db, &allocImp);

File_Close(&archiveStream.file);

if (res == SZ_OK)

{

LOGD("Everything is Ok\n");

return 0;

}

if (res == SZ_ERROR_UNSUPPORTED

)

LOGE("decoder doesn't support this archive\n");

else if (res == SZ_ERROR_MEM

)

LOGE("can not allocate memory\n");

else if (res == SZ_ERROR_CRC

)

LOGE("CRC error\n");

else

LOGE("ERROR #%d\n", res);

return 1;

}

int main(int numargs, char *args[])

{

return extract7z(args[1], args[2]);

}

我用的是Eclipse,使用Mingw编译。

执行效果,能正确解压。

这样的解压只能适用简单的解压,不支持加密,参数2的输出文件路径中的所有文件夹都必须存在,压缩包中文件夹不需要存在,解压时会自动创建。

压缩包中的文件夹不能为中文,否则乱码。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐