数据压缩技术常用于减少存储空间和网络传输负载。LZ4 是一种快速无损压缩算法,速度快,适合高性能场景。K4os.Compression.LZ4
是为 .NET 平台设计的 LZ4 实现,支持 .NET Core、.NET Framework、Mono、Xamarin 和 UWP。本文介绍该库的功能、用法、性能和与其他算法的对比。
LZ4 是一种由 Yann Collet 开发的快速无损压缩算法。压缩速度约为 400 MB/s 单核,解压速度达 2 GB/s,接近内存速度极限。相比传统压缩算法(如 zlib 和 lzma),LZ4 速度快,适合实时压缩场景,如网络传输或文件存取。
测试数据(Silesia Corpus)如下
LZ4 速度远超传统算法,压缩率稍低,但在高吞吐量场景表现优异。
K4os.Compression.LZ4
是一个基于 .NET Standard 2.0+ 的开源库,兼容 .NET Framework 4.6.2+ 和 .NET 5.0+。它提供三种功能包:
包名 | NuGet 链接 | 功能描述 |
---|---|---|
K4os.Compression.LZ4 | NuGet | 块压缩 |
K4os.Compression.LZ4.Streams | NuGet | 流压缩 |
K4os.Compression.LZ4.Legacy | NuGet | 兼容旧版 lz4net 格式 |
K4os.Compression.LZ4
支持块压缩和流压缩,适用于不同场景。
块压缩适合处理固定大小的数据块,如网络包。
库支持多种压缩级别,定义在 LZ4Level
枚举中:
enum LZ4Level
{
L00_FAST, // 快速模式,最高压缩速度
L03_HC, L04_HC, L05_HC, L06_HC, L07_HC, L08_HC, L09_HC, // 高压缩模式
L10_OPT, L11_OPT, L12_MAX // 优化模式,最高压缩率
}
解压速度不受压缩级别影响,高压缩级别数据解压更快,因数据量小。
LZ4Codec
类提供 MaximumOutputSize(int length)
方法,计算压缩后数据最大大小。用于分配目标缓冲区,因不可压缩数据可能比原始数据大。
使用 LZ4Codec.Encode
进行块压缩:
var source = new byte[1000]; // 源数据
var target = new byte[LZ4Codec.MaximumOutputSize(source.Length)]; // 目标缓冲区
var encodedLength = LZ4Codec.Encode(
source, 0, source.Length,
target, 0, target.Length,
LZ4Level.L00_FAST); // 快速模式
encodedLength
表示压缩后数据长度。负值表示压缩失败,通常是目标缓冲区过小。
解压需知道原始数据大小,压缩数据不含此信息。示例:
var source = new byte[1000]; // 压缩数据
var target = new byte[knownOutputLength]; // 需知道原始大小
var decodedLength = LZ4Codec.Decode(
source, 0, source.Length,
target, 0, target.Length);
需自行存储原始数据大小,或使用 LZ4Pickler
或 LZ4Stream
。
LZ4Pickler
适合快速压缩小数据块,如网络消息。自动存储原始数据长度,处理不可压缩数据。
示例:
var source = new byte[1000];
var encoded = LZ4Pickler.Pickle(source, LZ4Level.L00_FAST);
var decoded = LZ4Pickler.Unpickle(encoded);
LZ4Pickler
方便,但性能略低于手动块压缩,可能有额外内存分配。
流压缩适合处理连续数据流,如文件或网络流,通过 K4os.Compression.LZ4.Streams
包实现。依赖 K4os.Hash.xxHash
,兼容 LZ4 Frame 格式。
LZ4EncoderSettings
类配置压缩参数:
class LZ4EncoderSettings
{
long? ContentLength { get; set; } = null; // 未支持
bool ChainBlocks { get; set; } = true; // 块链接
int BlockSize { get; set; } = Mem.K64; // 块大小
bool ContentChecksum { get; set; } = false; // 内容校验
bool BlockChecksum { get; set; } = false; // 块校验
uint? Dictionary => null; // 未支持
LZ4Level CompressionLevel { get; set; } = LZ4Level.L00_FAST; // 压缩级别
int ExtraMemory { get; set; } = 0; // 额外内存
}
默认设置够用,可调整块大小或校验选项。
使用 LZ4Stream.Encode
创建压缩流
using (var source = File.OpenRead("input.txt"))
using (var target = LZ4Stream.Encode(File.Create("input.txt.lz4")))
{
source.CopyTo(target);
}
解压设置简单,通过 LZ4DecoderSettings
配置额外内存
class LZ4DecoderSettings
{
int ExtraMemory { get; set; } = 0;
}
解压示例
using (var source = LZ4Stream.Decode(File.OpenRead("input.txt.lz4")))
using (var target = File.Create("output.txt"))
{
source.CopyTo(target);
}
流解压兼容 LZ4 Frame 格式,忽略未实现功能(如内容校验),不影响解压。
版本 1.3-beta 引入 ILZ4FrameReader
和 ILZ4FrameWriter
接口,支持 Span
、Memory
、Stream
等数据结构的压缩和解压。通过 LZ4Frame
类工厂方法创建。
示例(内存解压):
var decoded = LZ4Frame.Decode(encoded.AsSpan(), new ArrayBufferWriter<byte>()).WrittenMemory.ToArray();
比传统流方式快,内存分配少,适合小数据块。
K4os.Compression.LZ4.Legacy
包支持旧版 lz4net
文件格式,允许读写旧格式文件。
示例(转换旧格式到新格式):
using (var source = LZ4Legacy.Decode(File.OpenRead("input.old")))
using (var target = LZ4Stream.Encode(File.Create("input.new")))
{
source.CopyTo(target);
}
库默认启用内存池,减少分配开销。长期运行的流可能因固定内存有问题。可通过 PinnedMemory.MaxPooledSize
调整池大小,设为 0 禁用。
小数据帧(如网络包)使用 LZ4Frame
更高效。测试显示 LZ4Frame.Decode
比流方式快约 2 倍,内存分配少:
方法 | 数据大小 | 平均时间 (ns) | 内存分配 (Gen0) |
---|---|---|---|
UseStream | 128 | 1173.6 | 1.2703 |
UseFrameReader | 128 | 466.2 | 0.0525 |
ARMv7 架构(如 Unity 的 IL2CPP)下,库使用对齐内存访问避免崩溃。可通过 LZ4Codec.Enforce32 = true
强制 32 位模式,确保兼容性。
LZ4 不是唯一的快速压缩算法。其他算法包括:
https://github.com/MiloszKrajewski/K4os.Compression.LZ4