7-zip 下lzma数据解压缩方式

那些踩过得神坑:<备注,这个demo的例子有一处是不对的.>

LzmaDecode中的第四个参数:nCompBufLen 应该给第三个参数的实际缓冲区大小.!!!,我操.分析源码.和返回值,百度没有.


本文章介绍的是  LZMA SDK 9.20


7z LZMA 至少需要这三个源文件

LzmaEnc.c
LzmaDec.c
LzFind.c

和这五个头文件

LzFind.h
LzHash.h
LzmaDec.h
LzmaEnc.h
Types.h

LZMA2 需要在此基础上附加两个源文件

Lzma2Dec.c
Lzma2Enc.c

以及两个头文件

Lzma2Dec.h
Lzma2Enc.h

LZMA 流接口有 6 个函数,参数含义可顾名思义

CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc);
void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);

CLzmaEncHandle 实为 void *

SRes 为状态返回类型

ISzAlloc、ISeqInStream、ISeqOutStreaem 和 ICompressProgress 为用户需要提供的四个接口,它们的定义如下

typedef struct
{
void *(*Alloc)(void *p, size_t size);
void (*Free)(void *p, void *address); /* address can be 0 */
} ISzAlloc;

typedef struct
{
SRes (*Read)(void *p, void *buf, size_t *size);
/* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
(output(*size) < input(*size)) is allowed */
} ISeqInStream;

typedef struct
{
size_t (*Write)(void *p, const void *buf, size_t size);
/* Returns: result - the number of actually written bytes.
(result < size) means error */
} ISeqOutStream;

typedef struct
{
SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
/* Returns: result. (result != SZ_OK) means break.
Value (UInt64)(Int64)-1 for size means unknown value. */
} ICompressProgress;

另外注意在实现 ISeqInStream 时,除最后两次调用外,必须每次都提交 *size 字节的数据,最后两次中,一次提交所有剩余数据,另一次提交 0 字节表示结束,否则 LZMA Encoder 会崩溃。

还有一个 One-Call 接口,把上面的调用按照常规逻辑包装了一下

SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);

LZMA2 的接口与 LZMA 类似,主要不同之处有两点:

- alloc 和 allocBig 接口被放到了构造函数中
- props 中多了一些参数

http://www.7-zip.org/sdk.html

另外值得一提的是,LZMA 单线程在笔记本电池供电时,使用快速模式,对随机数据的压缩速度为 4MB/s,压缩率约为 100%,对全零数据的压缩速度为 70MB/s,压缩率约为 0%。 


经过SunOS sun280 5.10验证的实例(该实例为直接调用封装好的函数):

/* * Simple test program for LZMA SDK's "one call" interface. * */ 
#include <stdio.h> 
#include <string.h> 
#include "../../LzmaEnc.h" 
#include "../../LzmaDec.h" 
#include "../../Alloc.h" 

#define COMP_BUFLEN 1000 
#define UNCOMP_BUFLEN 5000 

char* pTestData; 
unsigned char pCompBuf[1000]; /* Compressed data */ 
unsigned char pUnCompBuf[5000]; /* Unompressed data - at the end its contents */ 
/* should be equal to contents of pTestData */ 
static void *SzAlloc(void *p, size_t size) { return MyAlloc(size); } 
static void SzFree(void *p, void *address) { MyFree(address); } 

int main(int argc, char* argv[]) 
{
     pTestData = "DEADBEEF|askjd9827x34bnzkj#%wioeruxo3b84nxijlhwqdzhwerzu39b87r#_3b9p78bznor83y4fr";
     size_t nTestDataLen = strlen(pTestData);
     size_t nCompBufLen = COMP_BUFLEN; 
     size_t nUnCompBufLen = UNCOMP_BUFLEN; 
     unsigned char pPropsBuf[LZMA_PROPS_SIZE]; 
     size_t nPropsBufLen = LZMA_PROPS_SIZE; 
     ISzAlloc stAllocator = { SzAlloc, SzFree }; 
     CLzmaEncProps stProps; 
     ELzmaStatus nStatus; 
     SRes rc;
     int err = 0; 
     memset(pCompBuf, 0, COMP_BUFLEN); 
     memset(pUnCompBuf, 0, UNCOMP_BUFLEN); /* Initialize compressor (aka encoder) properties... */ 
     
     LzmaEncProps_Init(&stProps); 
     stProps.level = 9; 
     stProps.dictSize = 1 << 24; 
     /* ... and compress data. */ 
     printf("dest_len:%d,src_len:%d,prop_len:%d\n",nCompBufLen,nTestDataLen,nPropsBufLen);
     
     
     rc = LzmaEncode(pCompBuf+LZMA_PROPS_SIZE, &nCompBufLen, (unsigned char*)pTestData, nTestDataLen, &stProps, pPropsBuf, &nPropsBufLen, 0, NULL, &stAllocator, &stAllocator); 
     if ( rc != SZ_OK )
      { 
       printf("\nLZMA compression failed (rc=%d).\n", rc); 
       err = 1; 
      }
      else
      {
      printf("dest_address:%p,dest_len:%d,src_len:%d,dest:%s\n",pCompBuf,nCompBufLen,nTestDataLen,pCompBuf+LZMA_PROPS_SIZE+1);
      }
       
     /* Decompress compressed data from previous step */ 
        //nCompBufLen += LZMA_PROPS_SIZE;
        nUnCompBufLen = nTestDataLen;
     rc = LzmaDecode(pUnCompBuf, &nUnCompBufLen, pCompBuf+LZMA_PROPS_SIZE, &nCompBufLen, pPropsBuf, nPropsBufLen, LZMA_FINISH_ANY, &nStatus, &stAllocator);
     
      if ( rc != SZ_OK )
          { 
           printf("\nLZMA decompression failed (rc=%d, status=%d).\n", rc, nStatus);
            err = 1;
          } 
          
      if ((nUnCompBufLen != nTestDataLen) || memcmp(pTestData, pUnCompBuf, nTestDataLen) )
           { 
           printf("Compression and/or decompression failed!\n"); 
            printf("\tInput data length [nTestDataLen] : %d\n", nTestDataLen); 
            printf("\tCompressed data length [nCompBufLen] : %d\n", nCompBufLen); 
            printf("\tUncompressed data length [nUnCompBufLen]: %d\n", nUnCompBufLen); 
          
          if ( memcmp(pTestData, pUnCompBuf, nTestDataLen) ) 
                printf("\tpTestData and pUnCompBuf contain different data!\n"); 
          else
             {
              printf("\ndest_len:%d\n,dest_data:%s\n,src_src:%s\n",nUnCompBufLen,pUnCompBuf,pTestData);
             }
             
             err = 1; 
           }
           
           printf("\ndest_len:%d\n,dest_data:%s\n,src_src:%s\n",nUnCompBufLen,pUnCompBuf,pTestData);
       
        if ( !err ) 
         printf("\nOK!\n");
        
          return 0;
        
}

详情请浏览sdk说明文档或者LZMA官方论坛(http://sourceforge.net/projects/sevenzip/forums/forum/45797/topic/4698263)

备注:
         

        整整三天才搞出来,今天终于可以好好睡觉了。学编程的同学啊,要加强英语的学习啊。

原文转载自:http://blog.163.com/linzhigui1988@126/blog/static/1018865812012499356225/

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要使用7-Zip库中的lzma压缩大文件,您需要遵循以下步骤: 1. 下载7-Zip SDK并解压缩到您的计算机。 2. 使用以下代码包含必要的头文件: ```c #include "lzma/LzmaEnc.h" #include "lzma/LzmaDec.h" ``` 3. 创建一个LzmaEncHandle和LzmaEncProps结构体来设置压缩选项: ```c LzmaEncHandle enc = LzmaEnc_Create(&g_Alloc); LzmaEncProps props; LzmaEncProps_Init(&props); props.level = 5; // 压缩级别 props.dictSize = 1 << 26; // 字典大小 props.reduceSize = (1 << 30) - 1; // 压缩后文件大小 props.lp = 0; // 用于匹配模式的扩展字节数 props.pb = 2; // 用于匹配模式的字节数 props.fb = 128; // 用于匹配模式的字节数 props.numThreads = 2; // 使用的线程数 ``` 4. 使用LzmaEnc_SetProps函数将压缩选项应用于LzmaEncHandle: ```c LzmaEnc_SetProps(enc, &props); ``` 5. 打开要压缩的大文件,并为输出文件创建一个文件句柄: ```c FILE* inFile = fopen("input_file", "rb"); FILE* outFile = fopen("output_file.lzma", "wb"); ``` 6. 编写循环,将文件分段读取并压缩: ```c int inSize = 1 << 16; // 每次读取的输入文件大小 int outSize = 1 << 16; // 每次写入的输出文件大小 unsigned char* inBuf = (unsigned char*)malloc(inSize); unsigned char* outBuf = (unsigned char*)malloc(outSize); while (true) { // 读取输入文件 size_t bytesRead = fread(inBuf, 1, inSize, inFile); if (bytesRead == 0) { break; } // 压缩数据 size_t outPos = 0; size_t outLen = outSize; LzmaEnc_Encode(enc, outBuf, &outLen, inBuf, bytesRead, &g_Alloc, &g_Alloc); // 写入输出文件 fwrite(outBuf, 1, outLen, outFile); } ``` 7. 关闭文件句柄和LzmaEncHandle,并释放内存: ```c fclose(inFile); fclose(outFile); LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc); free(inBuf); free(outBuf); ``` 这样,您就可以使用7-Zip库中的lzma压缩大文件了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值