zstd-rs

KillingSparkMIT活跃维护

纯 Rust 实现的 Zstandard 压缩格式库,让 Rust 项目无需依赖 C 库就能做 zstd 压缩和解压。

zstd format implementation in pure rust

v0.9.1发布于 2026-10-11 13:11 UTC458star74fork同步于 2026-11-10 11:59 UTC

怎么上手

由 README 提炼,执行前请确认
cargo add ruzstd
硬件要求按 README 说明

README 未说明,纯 Rust 实现,不依赖 GPU 或显存

下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

纯 Rust 实现的 Zstandard 格式库,解压完整可用,压缩够用但不如官方 C 库快

纯 Rust 实现的 Zstandard 压缩格式库,让 Rust 项目无需依赖 C 库就能做 zstd 压缩和解压。

核心能力

  • 完整实现 RFC8878 的 Zstandard 解压
  • 提供 StreamingDecoder 流式解压并实现 io::Read
  • 支持低层 FrameDecoder 分块解码以控制内存
  • 压缩支持 Uncompressed 与 Fastest 级别并带校验和
  • 启用 dict_builder 特性可生成 raw content 字典

容易踩的坑

压缩端仅支持 Uncompressed 和 Fastest 级别,Default/Better/Best 及字典压缩尚未实现;字典生成只支持 raw content 字典,不支持 tagged 字典;解压用户提供的数据时帧可能极大,需自行检查帧大小或改用分块解码避免内存爆掉

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v0.9.1
  1. v0.9.1Window size fixes最新正式版2026-10-11 · 2026-10-11 13:11 UTC
    • Reduce memory footprint while decoding
    • Match zstd default maximum window size of 128MiB
    • Avoid decoding more bytes than allowed per block to protect agains malformed blocks triggering an OOM panic
  2. v0.9.0Make maximum window size configurable2026-07-26 · 2026-07-26 17:50 UTC
    查看更新说明
    • Avoid emitting compressed blocks when the compressed payload is not smaller than the raw block. (#105)
    • Fix Dictionary decoding. It should not panic on invalid inputs.
    • Make the decode window size limit configurable via FrameDecoder::set_max_window_size/max_window_size, StreamingDecoder::new_with_max_window_size, and the DEFAULT_MAX_WINDOW_SIZE constant. The default stays 100mb. (#111)
    • Apply the window size limit to the first frame of a stream, not just later frames. (#111)
    • Breaking FrameDecoderError::WindowSizeTooBig gained a max field and now reports the effective limit. (#111)
  3. v0.8.3Fix checksum generation when resuing compressor and no more big stack buffers2026-05-08 · 2026-05-08 12:37 UTC
    查看更新说明
    • Introduce the rust-version field
    • Fix checksum generation when repeatedly using the encoder
    • Expose decoding::Dictionary as public
    • Add Debug derive to CompressionLevel enum
    • Make RLE and Raw block decoding more efficient and not use intermediary buffer on the stack
  4. v0.8.2Change to cargo workspace, improve CLI and make FrameCompressor nameable2025-11-03 · 2025-11-03 09:20 UTC
    查看更新说明

    @zleyyij improved the CLI a ton and switched this repo to a cargo workspace so that the dependencies for the binary and the library can be separated.

    Also, the MatchGeneratorDriver is now exported so users are able to name it as the M in FrameCompressor<R, W, M>

  5. v0.8.1Checksum on compressor, compressor ratio improvements, and small decoder bugfix2025-05-03 · 2025-05-03 14:04 UTC
    查看更新说明
    • Checksum is now added in compressed frames if the hash feature is enabled
    • Some compression ratio improvements
    • The decoder had a small bug where inefficient encodings of zero sequences in a block where wrongly considered invalid

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    Ruzstd (a pure rust zstd format implementation)

    Released API docs CI

    What is this

    A pure Rust implementation of the Zstandard compression format, as defined in RFC8878.

    This crate contains a fully operational implementation of the decompression portion of the standard. It also provides a compressor which is usable, but it does not yet reach the speed, ratio or configurability of the original zstd library.

    This crate is currently actively maintained.

    Current Status

    Decompression

    The decoding module provides a complete implementation of a Zstandard decompressor.

    In terms of speed, ruzstd is behind the original C implementation which has a rust binding located here.

    Measuring with the 'time' utility the original zstd and my decoder both decoding the same enwik9.zst file from a ramfs, my decoder is about 3.5 times slower. Enwik9 is highly compressible, for less compressible data (like a ubuntu installation .iso) my decoder comes close to only being 1.4 times slower.

    Compression

    On the compression side:

    • Support for generating compressed blocks at any compression level
      • Uncompressed
      • Fastest (roughly level 1)
      • Default (roughly level 3)
      • Better (roughly level 7)
      • Best (roughly level 11)
    • Checksums
    • Dictionaries

    Dictionary Generation

    When the dict_builder feature is enabled, the dictionary module provides the ability to create new dictionaries.

    On the github-users sample set, our implementation benchmarks within 0.2% of the official implementation (as of commit 09e52d07340acdb2e13817b066e8be6e424f7258):

    uncompressed: 100.00% (7484607 bytes)
    no dict: 34.99% of original size (2618872 bytes)
    reference dict: 16.16% of no dict size (2195672 bytes smaller)
    our dict: 16.28% of no dict size (2192400 bytes smaller)
    

    The dictionary generator only provides support for creating "raw content" dictionaries. Tagged dictionaries are currently unsupported.

    See https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#dictionary-format for clarification.

    How can you use it?

    Compression

    The easiest is to use the provided compress/compress_to_vec functions

    use ruzstd::encoding::{compress, compress_to_vec, CompressionLevel};
    let data: &[u8] = todo!();
    // Either
    let mut compressed = Vec::new();
    compress(data, &mut compressed, CompressionLevel::Fastest);
    // or
    let compressed = compress_to_vec(data, CompressionLevel::Fastest);
    

    Or you can use the FrameDecoder manually to compress data. This allows you to process encoded data while it is being encoded instead of collecting into a big vector.

    Decompression

    Additionally to the descriptions and the docs you can have a look at the zstd / zstd_streaming binaries. They showcase how this library can be used.

    Easy

    The easiest is to wrap the io::Read into a StreamingDecoder which itself implements io::Read. It will decode blocks as necessary to fulfill the read requests

    use ruzstd::decoding::StreamingDecoder;
    use ruzstd::io::Read;
    
    let mut source: &[u8] = todo!("Get a reader from a File or any other source");
    let mut decoder = StreamingDecoder::new(&mut source).unwrap();
    
    let mut result = Vec::new();
    decoder.read_to_end(&mut result).unwrap();
    

    This might be a problem if you are accepting user provided data. Frames can be REALLY big when decoded. If this is the case you should either check how big the frame actually is or use the memory efficient approach described below.

    Memory efficient

    If memory is a concern you can decode frames partially. There are two ways to do this:

    Streaming decoder

    Use the StreamingDecoder and use a while loop to fill your buffer (see src/bin/zstd_stream.rs for an example). This is the recommended approach.

    Use the lower level FrameDecoder

    For an example see the src/bin/zstd.rs file. Basically you can decode the frame until either a given block count has been decoded or the decodebuffer has reached a certain size. Then you can collect no longer needed bytes from the buffer and do something with them, discard them and resume decoding the frame in a loop until the frame has been decoded completely.

    Roadmap

    1. More Performance optimizations
      1. sequence_decoding and reverse_bitreader::get_bits. Those account for about 50% of the whole time used in decoding
      2. Matching suffixes. This accounts for >60% of the whole time used in encoding
    2. Implement encoder features
      1. More levels
      2. Dictionaries
      3. Checksums

    Testing

    Tests take two forms.

    1. Tests using well-formed files that have to decode correctly and are checked against their originals
    2. Tests using malformed input that have been generated by the fuzzer. These don't have to decode (they are garbage) but they must not make the decoder panic

    Fuzzing

    Fuzzing has been done on

    1. Random input with no initial corpus
    2. The *.zst in /fuzz_decodecorpus

    You want to help fuzz?

    Use cargo +nightly fuzz run decode or some other fuzz target to run the fuzzer. It is seeded with files created with decodecorpus.

    If the fuzzer finds a crash it will be saved to the artifacts dir by the fuzzer. Run cargo test artifacts to run the artifacts tests. This will tell you where the decoder panics exactly. If you are able to fix the issue please feel free to do a pull request. If not please still submit the offending input and I will see how to fix it myself.

    Contributing

    Contributions will be published under the same MIT license as this project. Please make an entry in the Changelog.md file when you make a PR.

    AI Contributions

    Contributions may be created by using whatever tools you like. They must be read, verified and decided to be a value added to the project by a human (you! not a maintainer) before submitting a PR and the communication about the PR must be handled by a human and not an agent. This is meant to be more or less in the spirit of the LLVM policy adapted to a much smaller project.