首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

使用 XZ Utils 获得更高的压缩率--关于 liblzma API

使用 XZ Utils 获得更高的压缩率--关于 liblzma API

liblzma API关于 liblzma APIliblzma API 提供了 LZMA1/LZMA2 算法的实现,并具有类似于 Zlib 的 API 接口。也和 gzip、bzip2 一样 XZ Utils 是流压缩格式。通过 liblzma API 接口,可以相对简单的编程实现对数据的压缩和解压缩。
使用 liblzma API 压缩数据使用 liblzma 压缩数据的过程,大致过程如下。
  • 定义 lzma_stream 结构体变量并使用 LZMA_STREAM_INIT 初始化,这个 lzma_stream 结构体变量会在整个数据压缩过程中被使用。有点类似于 C 中标准库中文件处理使用的结构体 FILE 。                       
    1
    lzma_stream strm = LZMA_STREAM_INIT;




  • 调用 lzma_easy_encoder 函数做压缩准备工作。函数的第一参数是 lzma_stream. 结构体变量的指针,第二参数则指明了期望压缩率大小。有效值为 [0,9], 数字越高压缩率越高。第三参数是指明数据完整性检查方法,LZMA_CHECK_CRC64 可以满足大多数情况需要。当然,还有 LZMA_CHECK_CRC32, LZMA_CHECK_SH256 可供选择,或者使用 LZMA_CHECK_NONE 不进行 数据完整性检查。                        lzma_easy_encoder (&strm, 6, LZMA_CHECK_CRC64);
  • 通过设定 lzma_stream 结构体变量中的 next_in 和 avail_in 字段,指明待压缩的数据开始 地址和长度。                       
    1
    2
    strm.next_in  = in_buf;  //input buffer address.
    strm.avail_in = in_len;  //data length.




  • 通过设定 lzma_stream 结构体变量中的 next_out 和 avail_out 字段,指明存放压缩结果 buffer 地址和长度。                       
    1
    2
    strm.next_out = out_buf;  //output buffer address
    strm.avail_out = 4096;    //output buffer length.




  • 然后通过调用 lzma_code 函数来压缩数据,或结束压缩数据。lzma_code 函数有两个参数,第一个参数是 lzma_stream 指针。而第二个参数用来指明 lzma_code 的动作: LZMA_RUN: 进行数据处理; LZMA_FINISH: 结束数据处理。                       
    1
    2
    lzma_code (&strm, LZMA_RUN);    /* compress data */
    lzma_code (&strm, LZMA_FINISH); /* Finish operation.*/




  • 最后要调用 lzma_end 函数释放资源,退出。                       
    1
    lzma_end(&strm);




下面是一段完整的示例程序。所示程序从标准输入 (stdin) 读入数据,压缩后写到标准输出 (stdout). 为了更便于理解压缩过程,示例代码省略了所有的异常处理和一些其他次要细节。
清单 1. 压缩数据的代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>
#include <lzma.h>

void xz_compress (FILE *in_file, FILE *out_file) {
   lzma_check check = LZMA_CHECK_CRC64;
   /* alloc and init lzma_stream struct */
   lzma_stream strm = LZMA_STREAM_INIT;
   
   uint8_t in_buf [4096];
   uint8_t out_buf [4096];
   bool in_finished = false;

   /* initialize xz encoder */
   lzma_easy_encoder (&strm, 6, LZMA_CHECK_CRC64);
   while (! in_finished) {
       /* read incoming data */
       size_t in_len = fread (in_buf, 1, 4096, in_file);

       if (feof (in_file))  {
           in_finished = true;
       }

       strm.next_in = in_buf;
       strm.avail_in = in_len;

       /* if no more data from in_buf, flushes the internal xz buffers and
        * closes the xz data with LZMA_FINISH */
       lzma_action action = in_finished ? LZMA_FINISH : LZMA_RUN;

       /* loop until there's no pending compressed output */
       do {
           strm.next_out = out_buf;
           strm.avail_out = 4096;

           lzma_code (&strm, action); /* compress data */

           size_t out_len = 4096 - strm.avail_out;
           fwrite (out_buf, 1, out_len, out_file); /* write compressed data */
       }while (strm.avail_out == 0);
   }

lzma_end (&strm);
}

int main () {
xz_compress (stdin, stdout);
return 0;
}




编译命令 :
1
$ gcc -g -o xz_pipe_mini xz_pipe_comp_mini.c -llzma




使用例子 :
1
$ cat a.txt | xz_pipe_mini > a.txt.xz




使用 liblzma API 解压数据使用 liblzma 进行解压缩的过程和压缩数据的过程基本一致。主要的区别是使用 lzma_stream_decoder 函数代替 lzma_easy_decoder 函数来进行 decoder 的初始化。
1
lzma_stream_decoder (&strm, memory_limit, flags);




lzma_stream_decoder 函数的第一参数是数是 lzma_stream 结构体变量的指针。第二参数则指明了在解压缩过程中使用内存的最大值。若 UINT64_MAX 则为不限制内存使用量。第三参数用来指明一些其他 flags 值:
  • LZMA_TELL_NO_CHECK: 如果压缩数据流中未指明数据完整性检查方式,则函数 lzma_code 返回 LZMA_TELL_NO_CHECK 。
  • LZMA_TELL_UNSUPPORTED_CHECK: 如果压缩数据流使用了不被支持的数据完整性检查方式,则函数 lzma_code 会返回 LZMA_TELL_UNSUPPORTED_CHECK 。
  • LZMA_CONCATENATED: 支持多个压缩流连接到一个 xz 文件内。
下面是一段完整的示例程序。所示程序从标准输入 (stdin) 读入数据,解压缩的数据写到标准输出 (stdout). 示例代码省略了所有的异常处理和一些其他次要细节。
清单 2. 解压缩数据的代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>
#include <lzma.h>
#define IN_BUF_MAX    4096
#define OUT_BUF_MAX   4096
#define RET_OK        0
#define RET_ERROR     1

int xz_decompress (FILE *in_file, FILE *out_file) {
   /* alloc and init lzma_stream struct */
   lzma_stream strm = LZMA_STREAM_INIT;
   uint8_t in_buf [IN_BUF_MAX];
   uint8_t out_buf [OUT_BUF_MAX];
   bool in_finished = false;
   bool out_finished = false;
   lzma_action action;
   lzma_ret ret_xz;
   int ret;

   ret = RET_OK;

   /* initialize xz decoder */
   ret_xz = lzma_stream_decoder (&strm, UINT64_MAX,
                       LZMA_TELL_UNSUPPORTED_CHECK|LZMA_CONCATENATED );  
   if (ret_xz != LZMA_OK)
       return RET_ERROR;

   while ((! in_finished) && (! out_finished)) {
       /* read incoming data */
       size_t in_len = fread (in_buf, 1, IN_BUF_MAX, in_file);

       if (feof (in_file))
           in_finished = true;

       strm.next_in = in_buf;
       strm.avail_in = in_len;

       /* if no more data from in_buf, flushes the
          internal xz buffers and closes the decompressed data
          with LZMA_FINISH */
       action = in_finished ? LZMA_FINISH : LZMA_RUN;

       /* loop until there's no pending decompressed output */
       do {
           /* out_buf is clean at this point */
           strm.next_out = out_buf;
           strm.avail_out = OUT_BUF_MAX;

           /* decompress data */
           ret_xz = lzma_code (&strm, action);

           if ((ret_xz != LZMA_OK) && (ret_xz != LZMA_STREAM_END)) {
               out_finished = true;
               ret = RET_ERROR;
           } else {
               /* write decompressed data */
               size_t out_len = OUT_BUF_MAX - strm.avail_out;
               fwrite (out_buf, 1, out_len, out_file);
               if (ferror (out_file)) {
                   out_finished = true;
                   ret = RET_ERROR;
               }
           }
       } while (strm.avail_out == 0);
   }

   lzma_end (&strm);
   return ret;
}

int main () {
   return xz_decompress (stdin, stdout);
}




编译命令:
1
$ gcc -g -o xz_pipe_decomp_mini xz_pipe_decomp_mini.c -llzma




使用例子:
1
$ cat a.txt.xz | xz_pipe_decomp_mini > a.txt

返回列表