准备
从网上下载bzip2库,我下载的是V1.0.8版本的。
然后在C工程中添加一个筛选器(文件夹)名叫bzlib
,然后把下载的库中的如下9个文件,添加到其中:
代码
主函数代码如下:
#include <stdio.h>
#include "bzlib/bzlib.h"
int main()
{
FILE* f; //用来接收打开文件的句柄
BZFILE* b; //用来接收库函数:BZ2_bzReadOpen打开的文件
char buf[1024]; //用来接收库函数:BZ2_bzRead读取出的字节
int bzerror; //用来接收库抛出的成功/错误代码
int nOpen; //用来接收BZ2_bzRead读取出的字节的长度
char fileName[] = "bz2/gbk.txt.bz2";
int stop = 1; //停止读取文件流的标志
f = fopen(fileName, "rb"); // 设置2进制只读
if (f == NULL) {
printf("文件不存在");
return;
}
b = BZ2_bzReadOpen(
&bzerror, // 错误码
f, // 文件指针
0, // 范围0-4,数字越大,monitoring/debugging输出越冗长
1, // 设置为不为0的数,则使用另一种压缩算法,这种算法少一半的内存消耗,代价是速度变慢
NULL, // 不使用
0 // 不使用
);
while (stop) {
if (bzerror == BZ_OK) // 成功打开
{
int num = sizeof(buf);
nOpen = BZ2_bzRead(&bzerror, b, buf, num);
if (bzerror == BZ_OK) { //读取成功
for (int i = 0; i < sizeof(buf); i++) { //以字符形式循环打印出读到的字节
printf("%c", buf[i]);
}
}
else if (bzerror == BZ_STREAM_END) { //读到了文件流(库手册中称为逻辑流)的末尾
for (int i = 0; i < nOpen; i++) { //以字符形式循环打印出读到的字节
printf("%c", buf[i]);
}
stop = 0; //退出循环读取
}
else if (bzerror == BZ_MEM_ERROR)
{
printf("没有足够的内存可用");
}
else { //其他情况
printf("读取遇到错误,错误码:%d", bzerror);
}
}
else // 打开失败立即关闭文件
{
BZ2_bzReadClose(&bzerror, b);
}
}
//关闭文件
BZ2_bzReadClose(&bzerror, b);
fclose(f);
}
其中最重要的点是: BZFILE* b
这个结构体接收BZ2_bzReadOpen
返回的结构体,其中包含了许多的信息。我们使用BZ2_bzRead
读取的话,无需关注读取的文件的大小,每次读取到了哪个字节,因为这些信息都在被BZFILE* b
内部记录了,我们只需要循环调用BZ2_bzRead
,把b
传进去即可。它会自动往下读,我们在每次读取完成后,把缓冲区的字节拿出来即可。注意检查bzerror == BZ_MEM_ERROR
,如果相等,说明读到了文件末尾。这时需要关闭循环读取。并且关闭文件。
测试
首先在工程所在的文件夹下创建一个文件夹bz2
,然后使用vscode在其中创建一个文件bgk.txt
,在其中输入一些文字:
中文测试:你好世界!
数字测试:123456
English:hello world!
使用vscode的原因是它能方便地改变文件的编码,所以使用其他的文本编辑器也可以。
更改这个文件为gbk
编码,因为控制台输出是gbk
格式。
然后使用压缩软件把gbk.txt
打一个.bz2
的压缩包。打包完成的文件名应该是gbk.txt.bz2
,这个压缩包在bz2
文件夹。上述代码中,文件名fileName[]
赋值为 "bz2/gbk.txt.bz2"
,这样代码就能找到这个文件了。
然后执行代码,可以看到控制台输出了gbk.txt
的内容,说明解压成功:
本文使用了libbzip2库(即bzlib.h)中高级接口的三个函数:BZ2_bzReadOpen、BZ2_bzRead、BZ2_bzReadClose。其他低级接口、高级接口、通用接口的函数暂没有使用。可详阅官方手册:https://sourceware.org/bzip2/manual/manual.html
搭配DeepL翻译使用更佳。