Board logo

标题: 使用 XZ Utils 获得更高的压缩率--关于 liblzma API [打印本页]

作者: look_w    时间: 2018-1-10 11:16     标题: 使用 XZ Utils 获得更高的压缩率--关于 liblzma API

liblzma API关于 liblzma APIliblzma API 提供了 LZMA1/LZMA2 算法的实现,并具有类似于 Zlib 的 API 接口。也和 gzip、bzip2 一样 XZ Utils 是流压缩格式。通过 liblzma API 接口,可以相对简单的编程实现对数据的压缩和解压缩。
使用 liblzma API 压缩数据使用 liblzma 压缩数据的过程,大致过程如下。
下面是一段完整的示例程序。所示程序从标准输入 (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 值:
下面是一段完整的示例程序。所示程序从标准输入 (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






欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0