zstd-rs

gyscosBSD-3-Clause活跃维护

Rust 对 zstd 压缩库的绑定,让 Rust 程序能直接调用 zstd 做高速压缩和解压,省去自己写 FFI 的麻烦。

A rust binding for the zstd compression library.

v0.14.2发布于 2026-10-10 13:52 UTC667star +1 / 7 天143fork同步于 2026-11-10 17:57 UTC

怎么上手

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

README 未说明显存或 GPU 要求;为纯 CPU 压缩库,支持 Linux/Windows/macOS 及 wasm 构建。

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

项目说明

由 README 自动翻译提炼

zstd 压缩库的 Rust 绑定,提供 Read/Write 包装与 bulk 一次性 API

Rust 对 zstd 压缩库的绑定,让 Rust 程序能直接调用 zstd 做高速压缩和解压,省去自己写 FFI 的麻烦。

核心能力

  • 提供 Read/Write 流式编解码包装与 copy_encode/copy_decode 便捷函数
  • bulk 一次性 API 对已知长度的切片避免流式缓冲拷贝
  • 压缩时记录解压后大小,解压端可一次性分配输出缓冲
  • zstdmt 特性开启 C 库多线程压缩
  • 可选 rust-backend 用纯 Rust 移植替代 C 库

容易踩的坑

从源码克隆需加 --recursive 或执行 git submodule update --init 拉取 zstd 子模块;性能测试必须用 --release,debug 构建测的是包装层而非 zstd;启用 bindgen 特性需 Rust 1.71+ 与 libclang,rust-backend 需 Rust 1.89+ 且与 seekable 特性冲突

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

最近发版

5 个版本v0.14.2
  1. v0.14.2最新正式版2026-10-10 · 2026-10-10 13:52 UTC

    zstd 0.14.2

    This release adds decoder APIs that let archive libraries recover their readers without consuming more compressed input or losing ownership on initialization errors.

    • Add stream::read::Decoder::into_inner(), which returns the underlying reader at its current position without additional I/O. This supports raw copying of compressed archive entries. Addresses #381 and the regression reported in #380.
    • Add Decoder::try_new, try_with_buffer, try_with_dictionary, try_with_prepared_dictionary, and try_with_ref_prefix. These return Result<Self, (R, io::Error)>, preserving the original reader if decoder initialization fails. Addresses #382.
    • Return an I/O error if a streaming decoder cannot allocate its decompression context, instead of panicking.
    • Clarify that finish_frame() can stop before the end of a frame when decoded output remains unread.

    Decoder::finish() keeps its 0.14 behavior: it attempts to consume remaining frame input before returning the reader. Archive libraries that need to recover compressed bytes should use into_inner() and adopt the new try_* constructors where they need to retain the reader after initialization failure. Existing constructor signatures remain unchanged.

    Rust 1.64 remains supported.

  2. v0.14.02026-09-04 · 2026-09-04 19:04 UTC
    查看更新说明

    Breaking

    Fixed

    • Decoder::finish() now consumes the rest of the frame, so the reader is handed back positioned just after it (https://github.com/gyscos/zstd-rs/pull/251, https://github.com/gyscos/zstd-rs/issues/255). zstd can produce the last of the decoded data before it has read the frame epilogue, so a caller who stops reading once it has the bytes it wanted used to get its reader back pointing inside the frame. Note that finish() may now read from the underlying reader; Decoder::finish_frame() is the same operation with the error surfaced.
    • Read::read() with an empty buffer returns Ok(0) instead of an error (https://github.com/gyscos/zstd-rs/issues/318).

    New

  3. zstd-safe-8.0.0zstd-safe v8.0.02026-09-04 · 2026-09-04 19:04 UTC
    查看更新说明

    Breaking

    • CCtx::ref_cdict() and DCtx::ref_ddict() now borrow the dictionary for as long as the context. zstd stores the dictionary in the context by pointer and dereferences it on every later operation, so safe code could previously drop the dictionary and cause a use-after-free.
    • AdvancedSeekable no longer implements DerefMut (https://github.com/gyscos/zstd-rs/issues/366). Handing out a &mut Seekable let safe code mem::swap() the context out and leave the swapped-out one holding a pointer to a reader this type frees on drop. decompress() and decompress_frame() are available directly on AdvancedSeekable instead, and Deref still covers the read-only queries.

    Fixed

    • A context is no longer reused after an error left it in a state zstd considers undefined (https://github.com/gyscos/zstd-rs/issues/315). zstd documents calling the streaming functions again on such a context as undefined behaviour; they now return the original error until something resets the context.
    • Cursor positions are no longer truncated when converted to usize, which on a 32-bit target could turn an out-of-range position into a small in-range one and read or write the wrong part of the buffer.
    • Seekable::init_advanced() no longer leaks the boxed reader when initialization fails.

    Other

    • New cmake and vendored features, forwarded to zstd-sys.
    • ResetDirective derives Copy, Clone, Debug, PartialEq and Eq, like the crate's other parameter enums.
    • The Send and Sync impls carry safety comments explaining why they hold.
  4. zstd-sys-2.1.0zstd-sys v2.1.02026-09-04 · 2026-09-04 19:04 UTC
    查看更新说明

    Breaking

    New

    Fixed

  5. v0.13.02023-10-11 · 2023-10-11 15:46 UTC
    查看更新说明

用户点评

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

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

    README 原文

    未翻译

    zstd

    crates.io BSD-3-Clause licensed

    Build on Linux Build on Windows Build on macOS Build on wasm

    This library is a rust binding for the zstd compression library.

    Documentation

    1 - Add to cargo.toml

    $ cargo add zstd
    
    # Cargo.toml
    
    [dependencies]
    zstd = "0.14"
    

    2 - Usage

    This library provides Read and Write wrappers to handle (de)compression, along with convenience functions to made common tasks easier.

    For instance, stream::copy_encode and stream::copy_decode are easy-to-use wrappers around std::io::copy. Check the stream example:

    use std::io;
    
    // This function use the convenient `copy_encode` method
    fn compress(level: i32) {
        zstd::stream::copy_encode(io::stdin(), io::stdout(), level).unwrap();
    }
    
    // This function does the same thing, directly using an `Encoder`:
    fn compress_manually(level: i32) {
        let mut encoder = zstd::stream::Encoder::new(io::stdout(), level).unwrap();
        io::copy(&mut io::stdin(), &mut encoder).unwrap();
        encoder.finish().unwrap();
    }
    
    fn decompress() {
        zstd::stream::copy_decode(io::stdin(), io::stdout()).unwrap();
    }
    

    Asynchronous support

    The async-compression crate provides an async-ready integration of various compression algorithms, including zstd-rs.

    Performance

    Which function to use

    The frame header can record how big the data will be once decompressed, and whoever reads it can then size their buffer in one go instead of growing it - worth roughly a factor of two to them. Only a compressor that knows the length up front can record it:

    you are compressinginto a Vecinto a Write
    a slice or a Vecbulk::compresscompress_sized_into
    a filecompress_filecompress_file_into
    a Read whose length you knowcompress_sizedcompress_sized_into
    any other Readencode_allcopy_encode

    Everything but the last row records the size, whatever it is. The last row records it when the source turns out to be shorter than 128 KiB, and leaves it out beyond that. Reach for the Write column when the data is large enough that you would rather not hold a Vec of it - these stream straight through, so only the compressor's own buffers are in memory. For a source that is neither a file nor a slice, its length is the one thing you have to supply yourself.

    On the way back, decode_all reads that header and sizes its output for you, and decompressed_size gives you the same number for a buffer of your own.

    Matching the C library

    This wrapper adds little over the C library. On the same data at level 3, a re-used bulk::Compressor and bulk::Decompressor land within a few percent of what zstd -b3 reports for the same file. If you are seeing much less than that, it is usually one of these:

    • A debug build. Always measure with --release; a debug build times this crate's wrappers rather than zstd.
    • Growing a Vec rather than sizing it. The convenience functions that return a Vec start from an empty one. On decompression, sizing the output up front - bulk::decompress, or copy_decode into a Vec::with_capacity - was worth roughly a factor of two in our measurements.
    • Streaming data that is already in memory. For a slice you already hold, the one-shot bulk API avoids a copy through the streaming buffers. It is worth about ten percent on decompression, so it is a much smaller effect than sizing the output - the Read/Write wrappers are not the problem people usually assume they are.
    • Leaving compression single-threaded. With the zstdmt feature and several workers, compression of a 33 MB input went about three times faster here. It is a loss on small inputs, where there is not enough data to keep the workers busy.

    To measure all of these on your own data:

    cargo run --release --features zstdmt --example throughput -- <file>
    

    It prints the matching zstd -b<level> command so you can compare against the C library directly.

    Cargo features

    Enabled by default: legacy, arrays, zdict_builder.

    FeatureDefaultDescription
    arraysyesUse fixed-size arrays ([u8; N]) as output buffers.
    legacyyesDecode frames written by zstd versions older than 0.8.
    zdict_builderyesTrain new dictionaries. Using a dictionary always works.
    experimentalExpose zstd's experimental API. It has no stability guarantees, and may change between zstd releases.
    zstdmtMulti-threaded compression inside the C library.
    thinBuild a smaller C library, at some cost in speed and error reporting.
    debugEnable zstd's debug logs.
    no_asmDo not build the x86-64 assembly.
    fat-lto, thin-ltoCross-language LTO. Only works if clang builds the C library.
    doc-cfgMark feature-gated items in the generated documentation. Needs a nightly compiler.
    wasmDoes nothing; kept so that existing dependants keep building.

    The following change how the C library is obtained or built:

    FeatureDefaultDescription
    bindgenGenerate the bindings at build time rather than using the pre-generated ones. Needs libclang.
    pkg-configLink against a system-installed libzstd instead of building the bundled source.
    vendoredAlways build the bundled source, even when pkg-config is also enabled. Useful to force a static build from a dependent crate.
    cmakeBuild the C library with zstd's own CMake files instead of the cc crate, which handles cross-compilation better. Needs cmake.
    rust-backendUse libzstd-rs-sys, a Rust port of zstd, instead of the C library. Experimental, see below.

    The zstd-sys readme also covers the build-time environment variables, and what to do if the linker complains about a hidden zstd symbol being "referenced by DSO".

    Compile it yourself

    zstd is included as a submodule. To get everything during your clone, use:

    git clone https://github.com/gyscos/zstd-rs --recursive
    

    Or, if you cloned it without the --recursive flag, call this from inside the repository:

    git submodule update --init
    

    Then, running cargo build should take care of building the C library and linking to it.

    Using Rust's global allocator

    By default, zstd allocates its internal state (compression windows, match finder tables, stream buffers, dictionaries) with the C runtime's malloc/free, invisible to a custom #[global_allocator].

    The with-rust-allocator feature makes every context and dictionary this crate creates (Encoder, Decoder, bulk::Compressor, dictionaries, ...) allocate through Rust's global allocator instead. It is crate-wide: enabling it in your own Cargo.toml also covers zstd usage inside your dependencies, since Cargo unifies features.

    zstd = { version = "0.14", features = ["with-rust-allocator"] }
    

    The feature implies experimental on zstd-safe because it relies on zstd's ZSTD_create*_advanced() constructors, which require static linking. It applies to contexts and prepared dictionaries created by the Rust wrappers, including clones. Direct calls to zstd_sys, dictionary training, legacy frame decoding, objects from the seekable format, and explicit zstd thread pools can still allocate through C.

    Prepared compression dictionaries use fixed parameters derived from their compression level and dictionary size. Unlike the default C constructor, the custom-allocator constructor does not store the level for later parameter adjustments based on the input size. Compressed output remains interoperable, but enabling this feature can change compression ratio, speed, and memory usage for prepared dictionaries, especially with large inputs and small dictionaries.

    Using the Rust port of zstd

    The rust-backend feature replaces the C library with libzstd-rs-sys, the Trifecta Tech Foundation's port of zstd to Rust. Nothing else changes: the port exports the same ZSTD_* functions that zstd-sys binds to, and this crate calls them the same way.

    zstd = { version = "0.14", features = ["rust-backend"] }
    

    Like the port itself, still a 0.0.1 prerelease, this is experimental:

    • The seekable format is not ported. Enabling both features is a compile error.
    • The features that configure the C build (thin, debug, no_asm, fat-lto, thin-lto, cmake, pkg-config and vendored) have no effect, and neither does ZSTD_SYS_USE_PKG_CONFIG.
    • Multithreading and legacy decoding are always built into the port: zstdmt only controls whether this crate exposes the multithreading API. The port decodes legacy frames from zstd 0.5 to 0.7, whether or not legacy is enabled, but not older ones.
    • The port allocates through Rust's global allocator, as with-rust-allocator does for the C library.
    • It still needs a C compiler on x86-64 Unix, where the port assembles one file, and it does not build for wasm32-unknown-unknown.
    • It needs Rust 1.89 or newer.
    • It is slower than the C library in most benchmarks: the pull request that added it has a chart. bench/backends.sh runs the same comparison on your machine.

    Build-time bindgen

    The bindgen feature requires Rust 1.71 or newer and libclang. The pre-generated bindings remain compatible with Rust 1.64.

    This library includes a pre-generated bindings.rs file. You can also generate new bindings at build-time, using the bindgen feature:

    cargo build --features bindgen
    

    TODO

    • Benchmarks, optimizations, ...

    Disclaimer

    This implementation is largely inspired by bozaro's lz4-rs.

    License

    • The zstd C library is under a dual BSD/GPLv2 license. Its decoders for legacy formats (the legacy feature, on by default) also include code under the BSD-2-Clause license.
    • This zstd-rs binding library is under a BSD-3-Clause license.