7Z压缩

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

可以在这里找到各种版本:http://zh.sourceforge.jp/projects/sfnet_sevenzip/releases/

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

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

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



修改7zMain.c即可

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

主要调用函数:

C代码 复制代码   收藏代码
  1. SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp);   
  2.   
  3. SRes SzAr_Extract(   
  4.     const CSzArEx *p,   
  5.     ILookInStream *inStream,   
  6.     UInt32 fileIndex,   
  7.     UInt32 *blockIndex,   
  8.     Byte **outBuffer,   
  9.     size_t *outBufferSize,   
  10.     size_t *offset,   
  11.     size_t *outSizeProcessed,   
  12.     ISzAlloc *allocMain,   
  13.     ISzAlloc *allocTemp);   
  14.       

 

我们先在Windows下编译:

完整代码如下:

C代码 复制代码   收藏代码
  1. /* 7zMain.c - Test application for 7z Decoder  
  2.  2008-11-23 : Igor Pavlov : Public domain */  
  3.   
  4. #include <stdlib.h>   
  5. #include <stdio.h>   
  6. #include <string.h>   
  7.   
  8. #define LOGD printf   
  9. #define LOGE printf   
  10.   
  11. #include "7zCrc.h"   
  12. #include "7zFile.h"   
  13. #include "7zVersion.h"   
  14.   
  15. #include "7zAlloc.h"   
  16. #include "7zExtract.h"   
  17. #include "7zIn.h"   
  18.   
  19. int MY_CDECL extract7z(const char* srcFile, const char* dstPath)   
  20. {   
  21.     CFileInStream archiveStream;   
  22.     CLookToRead lookStream;   
  23.     CSzArEx db;   
  24.     SRes res;   
  25.     ISzAlloc allocImp;   
  26.     ISzAlloc allocTempImp;   
  27.     char outPath[1024] = { 0 };   
  28.   
  29.     LOGD("7z ANSI-C Decoder " MY_VERSION_COPYRIGHT_DATE "\n");   
  30.   
  31.     if (InFile_Open(&archiveStream.file, srcFile)) {//open 7z file   
  32.         LOGE("can not open input file\n");   
  33.         return 1;   
  34.     }   
  35.   
  36.     FileInStream_CreateVTable(&archiveStream);   
  37.     LookToRead_CreateVTable(&lookStream, False);   
  38.   
  39.     lookStream.realStream = &archiveStream.s;   
  40.     LookToRead_Init(&lookStream);   
  41.   
  42.     allocImp.Alloc = SzAlloc;   
  43.     allocImp.Free = SzFree;   
  44.   
  45.     allocTempImp.Alloc = SzAllocTemp;   
  46.     allocTempImp.Free = SzFreeTemp;   
  47.   
  48.     CrcGenerateTable();   
  49.   
  50.     SzArEx_Init(&db);   
  51.     res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp);   
  52.   
  53.     if(res == SZ_OK)   
  54.     {   
  55.         Int32 i;   
  56.   
  57.         UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */  
  58.         Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */  
  59.         size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */  
  60.   
  61.         LOGD("Total file/directory count[%d]\n", db.db.NumFiles);   
  62.         for (i = db.db.NumFiles - 1; i >= 0; i--) {   
  63.             size_t offset;   
  64.             size_t outSizeProcessed;   
  65.             CSzFileItem *f = db.db.Files + i;   
  66.   
  67.             strcpy(outPath, dstPath);   
  68.             strcat(outPath, "/");   
  69.             strcat(outPath, f->Name);   
  70.   
  71.             if (f->IsDir) {  //dir   
  72.                 LOGD("dir [%s]\n", outPath);   
  73.                 mkdir(outPath);   
  74.                 continue;   
  75.             }else{  //file   
  76.                 LOGD("file [%s]\n", outPath);   
  77.                 res = SzAr_Extract(&db, &lookStream.s, i, &blockIndex,   
  78.                         &outBuffer, &outBufferSize, &offset, &outSizeProcessed,   
  79.                         &allocImp, &allocTempImp);   
  80.                 if (res != SZ_OK){   
  81.                     break;   
  82.                 }else{   
  83.                     CSzFile outFile;   
  84.                     size_t processedSize;   
  85.                     if (OutFile_Open(&outFile, outPath)) {   
  86.                         LOGE("can not open output file\n");   
  87.                         res = SZ_ERROR_FAIL;   
  88.                         break;   
  89.                     }   
  90.                     processedSize = outSizeProcessed;   
  91.                     if (File_Write(&outFile, outBuffer + offset, &processedSize)   
  92.                             != 0 || processedSize != outSizeProcessed) {   
  93.                         LOGE("can not write output file\n");   
  94.                         res = SZ_ERROR_FAIL;   
  95.                         break;   
  96.                     }   
  97.                     if (File_Close(&outFile)) {   
  98.                         LOGE("can not close output file\n");   
  99.                         res = SZ_ERROR_FAIL;   
  100.                         break;   
  101.                     }   
  102.                 }   
  103.             }   
  104.         }   
  105.         IAlloc_Free(&allocImp, outBuffer);   
  106.     }   
  107.     SzArEx_Free(&db, &allocImp);   
  108.   
  109.     File_Close(&archiveStream.file);   
  110.     if (res == SZ_OK)   
  111.     {   
  112.         LOGD("Everything is Ok\n");   
  113.         return 0;   
  114.     }   
  115.     if (res == SZ_ERROR_UNSUPPORTED   
  116.         )   
  117.         LOGE("decoder doesn't support this archive\n");   
  118.     else if (res == SZ_ERROR_MEM   
  119.         )   
  120.         LOGE("can not allocate memory\n");   
  121.     else if (res == SZ_ERROR_CRC   
  122.         )   
  123.         LOGE("CRC error\n");   
  124.     else  
  125.         LOGE("ERROR #%d\n", res);   
  126.     return 1;   
  127. }   
  128.   
  129. int main(int numargs, char *args[])   
  130. {   
  131.     return extract7z(args[1], args[2]);   
  132. }  

 

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

 

 

执行效果,能正确解压。

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

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



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在 Java 中使用 7z 压缩,可以使用第三方库 SevenZipJBinding。以下是一个简单的示例代码: ```java import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.SystemUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.github.junrar.Archive; import com.github.junrar.exception.RarException; import com.github.junrar.impl.FileVolumeManager; import com.github.junrar.rarfile.FileHeader; import net.sf.sevenzipjbinding.ExtractOperationResult; import net.sf.sevenzipjbinding.ISevenZipInArchive; import net.sf.sevenzipjbinding.SevenZip; import net.sf.sevenzipjbinding.SevenZipException; import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream; public class SevenZipUtils { private static final Logger LOGGER = LogManager.getLogger(SevenZipUtils.class); /** * 解压 7z 文件 * * @param srcFile * 压缩文件 * @param destDir * 目标目录 * @throws IOException * @throws SevenZipException */ public static void extract7z(File srcFile, File destDir) throws IOException, SevenZipException { LOGGER.info("Extracting {} to {}", srcFile, destDir); RandomAccessFileInStream inputStream = null; ISevenZipInArchive inArchive = null; try { inputStream = new RandomAccessFileInStream(srcFile.getAbsolutePath(), "r"); inArchive = SevenZip.openInArchive(null, inputStream); int numItems = inArchive.getNumberOfItems(); for (int i = 0; i < numItems; i++) { ExtractOperationResult result = null; String destFileName = null; do { if (result != null) { LOGGER.warn("Extracting {} failed, trying again", destFileName); try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } destFileName = inArchive.getProperty(i, ISevenZipInArchive.NM_FILE_NAME); if (StringUtils.isBlank(destFileName)) { LOGGER.warn("File name is blank, using default"); destFileName = FilenameUtils.getBaseName(srcFile.getName()) + "." + FilenameUtils.getExtension(srcFile.getName()) + "." + i; } destFileName = FilenameUtils.separatorsToSystem(destFileName); File destFile = new File(destDir, destFileName); if (destFile.exists()) { FileUtils.forceDelete(destFile); } if (inArchive.getArchiveFormat() == net.sf.sevenzipjbinding.ArchiveFormat.RAR) { FileVolumeManager fileVolumeManager = new FileVolumeManager(srcFile); Archive archive = new Archive(fileVolumeManager); FileHeader fileHeader = archive.getFileHeaders().stream().filter(fh -> destFileName.equals(fh.getFileNameString())).findFirst().get(); result = inArchive.extractSlow(i, fileHeader.getFileNameW(), destFile.getParent(), fileHeader.isEncrypted()); } else { result = inArchive.extractSlow(i, destFile); } } while (result != ExtractOperationResult.OK); } } finally { IOUtils.closeQuietly(inArchive); IOUtils.closeQuietly(inputStream); } } } ``` 需要注意的是,SevenZipJBinding 依赖于 7-Zip 命令行工具,因此需要先安装 7-Zip 并将其添加到环境变量中。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值