目录
1.Bundle 压缩库:您的压缩利器
2.bundle详细介绍
2.1.特性
2.2.常用压缩数据的API(API - data)
2.3. 压缩文件简单使用示例
2.5.解压缩文件简单使用示例
2.4.测试每种压缩算法的性能
1.Bundle 压缩库:您的压缩利器
探索压缩领域的万能工具
您是否还在为选择合适的压缩库而烦恼?是否厌倦了复杂且难以使用的工具?别再犹豫了,欢迎了解 Bundle 压缩库,它将为您提供无与伦比的压缩体验。Bundle 是一个轻巧、灵活的库,只需几行代码即可集成到您的项目中。它支持广泛的压缩算法和存档格式,让您轻松应对各种压缩需求。
算法选择:满足不同场景的压缩需求
Bundle 压缩库提供了 23 种不同的压缩算法,每种算法都有其独特的优点和缺点。在选择合适的算法时,您需要考虑压缩速度、压缩率和内存使用情况等因素。这里有一些流行算法的简要介绍:
- Zlib: 提供快速的压缩速度,适合快速处理大量数据的场景。
- Bzip2: 提供极高的压缩率,适合长期存储数据或处理大型数据集的情况。
- LZMA: 提供极高的压缩率,但压缩速度较慢。
- LZO: 速度非常快,适合处理大量数据流的场景。
无缝集成:节省时间和精力
Bundle 压缩库集成了所有必需的代码,无需进行额外的编译。您只需将 bundle.h 和 bundle.cpp 这两个文件添加到您的项目中即可。这种无缝的集成方式让您轻松快速地使用该库,从而节省大量时间和精力。
存档格式:支持多种场景
Bundle 压缩库支持两种存档格式:ZIP 和 TAR。ZIP 格式是一种通用的存档格式,可用于文件归档、备份和数据传输等各种场景。TAR 格式则更适合在 Linux 系统中进行归档,因为它具有较高的压缩率。
您不可或缺的压缩利器
如果您正在寻找一个功能强大、使用方便的压缩库,那么 Bundle 压缩库一定是您的理想选择。它具备以下优势:
- 轻巧、灵活
- 支持多种压缩算法
- 支持 ZIP 和 TAR 存档格式
- 无缝集成
- 易于使用
常见问题解答
1. Bundle 压缩库与其他压缩库有什么不同?
Bundle 压缩库最大的优势在于其全面性。它提供了一系列压缩算法和存档格式,能够满足各种压缩需求。此外,其无缝集成和易用性也使其脱颖而出。
2. 我可以使用 Bundle 压缩库做什么?
您可以使用 Bundle 压缩库执行各种压缩操作,包括文件压缩、解压缩、存档和解档。它适用于各种场景,如文件备份、数据传输和长期存储。
3. Bundle 压缩库的压缩率如何?
Bundle 压缩库支持多种压缩算法,每种算法都具有不同的压缩率。您可以根据您的需求选择合适的算法。例如,Bzip2 算法提供极高的压缩率,而 LZO 算法则提供快速的压缩速度。
4. Bundle 压缩库是否易于使用?
Bundle 压缩库非常易于使用。它集成了所有必需的代码,您可以轻松地将其添加到您的项目中。此外,该库提供了详细的文档和示例代码,帮助您快速上手。
5. Bundle 压缩库是免费的吗?
是的,Bundle 压缩库是完全免费且开源的。您可以自由地将其用于您的个人或商业项目。
2.bundle详细介绍
bundle是一个可嵌入的压缩库,支持23种算法和2种存档格式。
两种存档格式:
- 1 将所有文件加入压缩类,然后一起压缩。即 .zip
- 2 将每一个文件压缩后再加入压缩类,然后打包在一起。即 .bun
2.1.特性
- 存档支持:.bun , .zip。即两种压缩保存方式
- 流支持:DEFLATE, LZMA, LZIP, ZPAQ, LZ4, ZSTD, BROTLI, BSC, CSC, BCM, MCM, ZMOLLY, ZLING, TANGELO, SHRINKER, CRUSH, LZJB, BZIP2 and SHOCO
- 最优化压缩率
- 最优化压缩速度
- 支持配置、封装、字包含、混合、跨平台(C++03)
- 可选基础结构(C++ 11)
- ZLIB/LibPNG版权协议
压缩二进制数据的格式(Bundle stream format),即.zip 的数据格式
[0x00 ...] Optional zero padding (N bits)
[0x70 0x??] Header (8 bits). De/compression algorithm (8 bits)enum { RAW, SHOCO, LZ4F, MINIZ, LZIP, LZMA20, ZPAQ, LZ4, // 0..7BROTLI9, ZSTD, LZMA25, BSC, BROTLI11, SHRINKER, CSC20, // 7..14ZSTDF, BCM, ZLING, MCM, TANGELO, ZMOLLY, CRUSH, LZJB, // 15..22BZIP2 // 23..};
[vle_unpacked_size] Unpacked size of the stream (N bytes). Data is stored in a variablelength encoding value, where bytes are just shifted and added into abig accumulator until MSB is found.
[vle_packed_size] Packed size of the stream (N bytes). Data is stored in a variablelength encoding value, where bytes are just shifted and added into abig accumulator until MSB is found.
[bitstream] Compressed bitstream (N bytes). As returned by compressor.If possible, header-less bitstreams are preferred.
.bun的数据格式(Bundle .bun archive format)
- Files/datas are packed into streams by using any compression method (see above)
- Streams are archived into a standard ZIP file:- ZIP entry compression is (0) for packed streams and (1-9) for unpacked streams.- ZIP entry comment is a serialized JSON of (file) meta-datas (@todo).
- Note: you can mix streams of different algorithms into the very same ZIP archive.
注意:采用这种存档方式时,同一个压缩文件中,可以采用不同的压缩算法。
2.2.常用压缩数据的API(API - data)
其实最常见的就莫过于下面这些了
namespace bundle
{// low level API (raw pointers)bool is_packed( *ptr, len );bool is_unpacked( *ptr, len );unsigned type_of( *ptr, len );size_t len( *ptr, len );size_t zlen( *ptr, len );const void *zptr( *ptr, len );bool pack( unsigned Q, *in, len, *out, &zlen );bool unpack( unsigned Q, *in, len, *out, &zlen );// medium level API, templates (in-place)bool is_packed( T );bool is_unpacked( T );unsigned type_of( T );size_t len( T );size_t zlen( T );const void *zptr( T );bool unpack( T &, T );bool pack( unsigned Q, T &, T );// high level API, templates (copy)T pack( unsigned Q, T );T unpack( T );
}
- 完整的 API参考头文件bundle.h
注意是上面那个哦!!!
vim /root/bundle/bundle.h
这些函数的定义都在下面这个
通常使用它们都是将他们拷贝出来
2.3. 压缩文件简单使用示例
#include <iostream> // 引入标准输入输出流库
#include <fstream> // 引入文件输入输出流库
#include <string> // 引入字符串库
#include "bundle.h" // 引入自定义的bundle头文件,假设它提供了压缩和解压缩功能 int main(int argc, char* argv[]) // 程序的主入口,argc表示命令行参数数量,argv是参数值的数组
{ // 输出命令行参数的使用说明 std::cout << "argv[1] 是原始文件路径名称\n"; std::cout << "argv[2] 是压缩包名称\n"; // 检查命令行参数数量,如果少于3个(程序名和两个参数),则退出程序 if (argc < 3) { std::cerr << "错误:命令行参数不足。\n"; return -1; } // 从命令行参数中获取原始文件路径和压缩包文件名 std::string ifilename = argv[1]; std::string ofilename = argv[2]; // 创建并打开一个输入文件流,以二进制模式读取原始文件 std::ifstream ifs; ifs.open(ifilename, std::ios::binary); // 检查文件是否成功打开 if (!ifs.is_open()) { std::cerr << "错误:无法打开原始文件。\n"; return -1; } // 将文件读写位置指针移动到文件末尾,以获取文件大小 ifs.seekg(0, std::ios::end); // 获取当前文件读写位置指针的位置,即文件大小 size_t fsize = ifs.tellg(); // 检查文件是否为空 if (fsize == 0) { std::cerr << "警告:原始文件为空。\n"; ifs.close(); // 关闭文件,因为不需要读取内容 return -1; // 或者您可以选择继续处理空文件,这里选择退出 } // 将文件读写位置指针重新移动到文件开头,准备读取文件内容 ifs.seekg(0, std::ios::beg); // 创建一个字符串对象,并调整其大小以容纳整个文件内容 std::string body; body.resize(fsize); // 从文件中读取数据到字符串对象中 ifs.read(&body[0], fsize); // 检查是否成功读取了文件内容(通常这一步不是必需的,因为read会设置failbit如果读取失败) // 但是,由于我们之前已经检查了文件大小并且resize了字符串,所以这里读取失败的可能性很小 // 除非在读取过程中文件被外部修改或删除 if (!ifs) { std::cerr << "错误:读取文件内容时出错。\n"; ifs.close(); return -1; } // 使用bundle类的pack方法压缩文件数据 std::string packed = bundle::pack(bundle::LZIP, body); // 创建并打开一个输出文件流,以二进制模式写入压缩后的数据 std::ofstream ofs; ofs.open(ofilename, std::ios::binary); // 检查输出文件是否成功打开 if (!ofs.is_open()) { std::cerr << "错误:无法打开输出文件。\n"; return -1; } // 将压缩后的数据写入到输出文件中 ofs.write(&packed[0], packed.size()); // 关闭输入和输出文件流,释放资源 ifs.close(); ofs.close(); // 程序正常结束,返回0 return 0;
}
在C++中,ifstream 和 ofstream 是用于文件输入输出的两个类,它们分别继承自 istream 和 ostream 类。这两个类属于标准库中的 <fstream> 头文件。
ifstream(input file stream):用于从文件中读取数据。
- 你可以使用 ifstream 对象打开一个文件,并像处理标准输入(std::cin)一样处理它,读取字符、行或格式化数据。
- 在代码中,ifstream ifs; 被用来打开并读取原始文件的内容。
ofstream(output file stream):用于向文件中写入数据。
- 你可以使用 ofstream 对象打开一个文件,并像处理标准输出(std::cout)一样处理它,写入字符、行或格式化数据。
- 在代码中,ofstream ofs; 被用来打开并写入压缩后的数据到压缩包文件。
在程序中,这两个类被用来:
- 使用 ifstream 读取用户指定的原始文件(argv[1]),将其内容加载到内存中的 std::string body 变量里。
- 使用 ofstream 将压缩后的数据(packed)写入到用户指定的压缩包文件(argv[2])中。
这两个步骤分别对应于文件的读取(输入)和写入(输出)操作。ifstream 和 ofstream 提供了方便的文件处理接口,使得文件读写操作更加直观和易于理解。
当你调用 ifs.read(&body[0], fsize); 时,你需要提供一个指向要读取数据的目标内存位置的指针,以及要读取的字节数。&body[0] 是获取 body 字符串中第一个字符的地址的一种方式。由于 std::string 在内部是以连续的内存块存储字符的,因此 &body[0] 实际上是指向 body 所分配的内存块的起始地址的指针。
这里使用 &body[0] 而不是 body.data() 或 body.c_str() 的原因是:
- body.data() 是在C++11及更高版本中引入的,它返回一个指向字符串数据的指针,该指针是 const char* 类型(除非你使用 std::string::mutable_data(),但这不是标准方法,且在某些实现中可能不存在)。由于 ifs.read 需要一个非 const 的指针来写入数据,所以直接使用 body.data() 在这里是不合适的(尽管在某些实现中,编译器可能会允许你通过 const_cast 来绕过这个限制,但这并不是一个好的做法)。
- body.c_str() 返回一个指向以空字符结尾的字符串的指针,它主要用于C风格的字符串操作,并且返回的指针也是 const char* 类型。
在C++98和C++03中,没有 std::string::data() 方法,所以 &body[0] 是获取字符串内部数据指针的常用方法。即使在C++11及更高版本中,&body[0] 仍然是一个有效且常用的方法来获取指向 std::string 内部数据的非 const 指针。
因此,在你的代码中,&body[0] 被用作 ifs.read 方法的参数,以指定数据应该被读取到的内存位置。
我们编译运行一下看看
g++ main.cc bundle.cpp -o test
运行结果如下
我们仔细看一下就会发现
线程?
g++ main.cc bundle.cpp -o test -lpthread
虽然出现了很多警告,我们不需要去管它!!!!
接下来我们将压缩下面这个文件
怎么样?压缩成功了吧!!
2.5.解压缩文件简单使用示例
main.cc
#include <iostream>
#include <fstream>
#include <string>
#include "bundle.h"int main(int argc, char* argv[])
{if(argc < 3){printf("argv[1]是压缩包名称\n");printf("argv[2]是解压缩后的文件\n");return -1;}std::string ifilename = argv[1]; // 压缩包名std::string ofilename = argv[2]; // 解压缩后文件名std::ifstream ifs;ifs.open(ifilename, std::ios::binary); // 打开压缩文件ifs.seekg(0, std::ios::end); // 跳转到读写位置到文件末尾size_t fsize = ifs.tellg(); // 获取末尾偏移量--获取文件长度ifs.seekg(0, std::ios::beg); // 返回到文件起始std::string body;body.resize(fsize); // 调整body大小为文件大小ifs.read(&body[0], fsize); // 读取压缩文件所有内容到bodyifs.close();std::string unpacked = bundle::unpack(body); // 进行解压缩,将解压缩后的数据保存到unpack中std::ofstream ofs;ofs.open(ofilename, std::ios::binary); // 打开文件ofs.write(&unpacked[0], unpacked.size()); // 将解压缩后的数据写入文件ofs.close();return 0;
}
编译过程和上面一样,接下来我们将使用这个来解压缩我们刚刚压缩的文件
首先就是它们的大小都一样。其次我们接着验证一下
MD5SUM是一个在Linux系统下广泛使用的命令,它用于计算和校验文件的MD5校验码。以下是对MD5SUM的详细解释:
一、基本概念
- MD5算法:全称是报文摘要算法(Message-Digest Algorithm 5),此算法对任意长度的信息逐位进行计算,产生一个二进制长度为128位(十六进制长度就是32位)的“指纹”(或称“报文摘要”)。不同的文件产生相同的报文摘要的可能性非常小。
- MD5校验码:通过MD5算法计算得到的文件的唯一标识,通常用于验证文件的完整性和防止文件被篡改。
二、功能
- 计算MD5校验码:通过MD5SUM命令,可以计算指定文件的MD5校验码,并将结果显示在终端上。
- 校验文件:可以将计算得到的MD5校验码与预先保存的MD5校验码进行比较,以验证文件的完整性。如果两者一致,则说明文件没有被篡改;如果不一致,则说明文件可能已经被篡改或损坏。
三、使用方法
- 计算文件的MD5校验码:
md5sum filename
这个命令会计算指定文件(filename)的MD5校验码,并将结果显示在终端上。同时,也可以将结果重定向到一个文件中,以便后续使用。
- 将多个文件的MD5校验码输出到一个文件中:
md5sum *.iso > iso.md5
这个命令会计算当前目录下所有以.iso结尾的文件的MD5校验码,并将结果输出到iso.md5文件中。
- 校验文件:
md5sum -c filename.md5
这个命令会读取filename.md5文件中的MD5校验码,并与对应文件的实际MD5校验码进行比较。如果验证成功,则会输出“正确”;如果验证失败,则会输出相应的错误信息。
四、注意事项
- 在使用MD5SUM命令时,需要确保文件的完整性和真实性。如果文件在传输或存储过程中被篡改或损坏,那么计算得到的MD5校验码将会与原始校验码不一致。
- 虽然MD5算法在大多数情况下是可靠的,但它也存在一些局限性。例如,MD5算法已经被证明无法防止碰撞(即两个不同的文件可能会产生相同的MD5校验码)。因此,在一些对安全性要求较高的场合,可能需要使用更安全的哈希算法(如SHA-256)来替代MD5算法。
总的来说,MD5SUM是一个简单而有效的工具,可以帮助用户验证文件的完整性和防止文件被篡改。在Linux系统下,MD5SUM命令已经被广泛应用于各种场合中。
显然是两个文件是一样的
2.4.测试每种压缩算法的性能
首先我们需要讲我们的bundle.h复制到当前目录下面
现在我们就可以编写程序了
main.cc
#include <cassert> // 包含断言库,用于在代码中设置检查点
#include "bundle.h" // 包含bundle库的头文件,该库提供了压缩和解压缩的功能 int main() { using namespace bundle; // 使用bundle命名空间,避免在调用bundle库中的函数时需要前缀 using namespace std; // 使用std命名空间,避免在调用标准库中的函数时需要前缀 // 创建一个大约23MB的原始数据集 string original( "There's a lady who's sure all that glitters is gold" ); // 初始化原始字符串 for (int i = 0; i < 18; ++i) // 循环18次,用于增大字符串的大小 original += original + string( i + 1, 32 + i ); // 将原始字符串自身和一些额外的字符追加到原始字符串上,额外字符的ASCII码从32开始递增 // 定义一个向量,存储要测试的压缩算法的枚举值 vector<unsigned> libs { RAW, SHOCO, LZ4F, MINIZ, LZIP, LZMA20, ZPAQ, LZ4, BROTLI9, ZSTD, LZMA25, BSC, BROTLI11, SHRINKER, CSC20, BCM, ZLING, MCM, TANGELO, ZMOLLY, CRUSH, LZJB }; // 遍历压缩算法,进行压缩和解压缩测试 for( auto &lib : libs ) { // 使用范围for循环遍历libs向量中的每个算法枚举值 string packed = pack(lib, original); // 调用pack函数,将原始数据压缩为packed字符串 string unpacked = unpack(packed); // 调用unpack函数,将压缩数据解压缩为unpacked字符串(注意:这里假设unpack函数接受一个参数) // 打印原始数据大小、压缩后数据大小以及算法名称 cout << original.size() << " -> " << packed.size() << " bytes (" << name_of(lib) << ")" << endl; // 使用断言验证解压缩后的数据是否与原始数据相同 assert( original == unpacked ); // 如果不相同,程序将在此处终止 } // 如果所有断言都通过,则打印"All ok." cout << "All ok." << endl;
}
压缩算法的性能(on a regular basis)
Rank | Compression ratio | Fastest compressors | Fastest decompressors | Average speed | Memory efficiency |
---|---|---|---|---|---|
1st | 91.15% ZPAQ | 958.18MB/s RAW | 2231.20MB/s RAW | 1340.63MB/s RAW | tbd |
2nd | 90.71% MCM | 358.41MB/s LZ4F | 993.68MB/s LZ4 | 508.50MB/s LZ4F | tbd |
3rd | 90.02% TANGELO | 240.87MB/s SHRINKER | 874.83MB/s LZ4F | 334.57MB/s SHRINKER | tbd |
4th | 88.31% BSC | 223.28MB/s LZJB | 547.62MB/s SHRINKER | 267.57MB/s LZJB | tbd |
5th | 87.74% LZMA25 | 210.74MB/s ZSTDF | 382.52MB/s MINIZ | 246.66MB/s ZSTDF | tbd |
6th | 87.74% LZIP | 159.59MB/s SHOCO | 380.39MB/s ZSTD | 209.32MB/s SHOCO | tbd |
7th | 87.63% BROTLI11 | 40.19MB/s ZLING | 333.76MB/s LZJB | 65.40MB/s ZLING | tbd |
8th | 87.50% CSC20 | 33.67MB/s CRUSH | 304.06MB/s SHOCO | 60.29MB/s CRUSH | tbd |
9th | 87.15% BCM | 13.73MB/s ZSTD | 297.34MB/s ZSTDF | 26.51MB/s ZSTD | tbd |
10th | 86.44% ZMOLLY | 09.00MB/s BSC | 287.83MB/s CRUSH | 13.44MB/s BZIP2 | tbd |
11th | 86.17% LZMA20 | 08.51MB/s BZIP2 | 287.58MB/s BROTLI9 | 11.51MB/s BROTLI9 | tbd |
12th | 86.05% BROTLI9 | 06.77MB/s ZMOLLY | 246.88MB/s BROTLI11 | 10.78MB/s BSC | tbd |
13th | 85.27% BZIP2 | 05.87MB/s BROTLI9 | 175.54MB/s ZLING | 08.13MB/s LZ4 | tbd |
14th | 85.24% ZSTD | 05.21MB/s BCM | 118.49MB/s LZMA25 | 07.24MB/s MINIZ | tbd |
15th | 82.89% ZLING | 04.08MB/s LZ4 | 108.71MB/s LZMA20 | 06.73MB/s ZMOLLY | tbd |
16th | 81.68% MINIZ | 03.65MB/s MINIZ | 72.72MB/s CSC20 | 05.27MB/s LZMA20 | tbd |
17th | 77.93% ZSTDF | 02.70MB/s LZMA20 | 57.05MB/s LZIP | 04.90MB/s LZMA25 | tbd |
18th | 77.57% LZ4 | 02.50MB/s LZMA25 | 31.88MB/s BZIP2 | 04.83MB/s CSC20 | tbd |
19th | 77.37% CRUSH | 02.50MB/s CSC20 | 13.44MB/s BSC | 04.65MB/s BCM | tbd |
20th | 67.30% SHRINKER | 02.25MB/s MCM | 06.68MB/s ZMOLLY | 04.13MB/s LZIP | tbd |
21th | 63.30% LZ4F | 02.14MB/s LZIP | 04.20MB/s BCM | 02.29MB/s MCM | tbd |
22th | 59.37% LZJB | 01.15MB/s TANGELO | 02.34MB/s MCM | 01.17MB/s TANGELO | tbd |
23th | 06.42% SHOCO | 00.24MB/s BROTLI11 | 01.18MB/s TANGELO | 00.48MB/s BROTLI11 | tbd |
24th | 00.00% RAW | 00.23MB/s ZPAQ | 00.21MB/s ZPAQ | 00.22MB/s ZPAQ | tbd |
注意:SHOCO是只能用于ASCII的文本压缩。通用压缩算法只有23种。