# @cjser/lzma1 中文文档

规范地址：https://npmcn.com/package/%40cjser/lzma1/

版本：0\.6\.3-cjser\.2
npm 元数据更新时间：2026-10-31T18:25:25.873Z
中文译文更新时间：2026-10-31T19:48:22.714Z
软件包许可：Apache-2\.0

本文由上游 README 机器翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40cjser/lzma1
原文对照：https://npmcn.com/package/%40cjser/lzma1/?lang=original
项目主页：https://github.com/xseman/lzma1
源码仓库：https://code.moenext.com/3rdeye/cjser

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：552 kB，85 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=18\.0\.0
- 运行依赖：0 个
- 首次发布：2026-05-07T06:10:29.357Z
- 最新版本发布：2026-10-31T18:25:25.629Z
- 已发布版本数：6（近 12 个月 6 个）

## 中文简介

一个JavaScript实现的Lempel-Ziv-Markov （LZMA）链压缩算法

## 安装

```sh
npm install @cjser/lzma1
```

也可以使用：`pnpm add @cjser/lzma1`、`yarn add @cjser/lzma1`、`bun add @cjser/lzma1`

## README

# lzma1

Lempel-Ziv-Markov链算法（LZMA）的TypeScript实现 为 `.lzma` 格式，从 [XZ代表Java](https://github.com/tukaani-project/xz-java)． 它也会解码 7z存档中的原始LZMA1和LZMA2数据 `.xz` 文件。它开始 作为一个 [叉](https://github.com/LZMA-JS/LZMA-JS) 的 [Nathan拉格的](https://github.com/nmrugg) LZMA-JS包。

## 为什么

JavaScript中有许多LZMA实现，但大多数都过时了， 没有维护，缺乏类型支持，或者依赖于特定的运行时api(例如， node . js `Buffer`）。

这个版本是XZ的Java移植版本，是LZMA的一个简洁实现 Collin和Igor Pavlov，通过LZMA SDK进行了一些优化。它是 兼容 `xz --format=lzma`， 7-Zip和LZMA SDK，并且只使用web 标准的api。

## 功能

-   编码和解码 `.lzma` 数据，可与 `xz`、7-Zip和LZMA SDK
-   将原始LZMA1和LZMA2数据解码为7z和 `.xz` 存储它，给定 容器中的属性
-   字符串（UTF-8）和二进制数据(`ArrayBuffer` 或任何类型数组)
-   异步压缩和解压缩与等待进度回调； 用于生产、进度和取消
-   压缩级别1-9或细粒度选项(字典大小， `lc`/`lp`/`pb`,……)
-   网页流(`TransformStream`)用于压缩和解压缩流
-   截断输入和大部分损坏输入的错误
-   不可信原始数据的内存限制，在KiB中，如Java的XZ
-   一个可选的输出大小限制，以防御“解压炸弹”攻击
-   没有依赖，运行在浏览器、worker、Node.js、Deno和Bun中

## 安装

> \[!请注意) 这个包是本地的 [ESM](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) 并且不再提供CommonJS 出口。如果你的项目使用CommonJS，你将不得不转换为ESM或使用 动态 [`import()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) 函数。

### [npm](https://npmjs.com/lzma1)

```sh
npm install lzma1
```

### 浏览器

```html
<script type="module">
    import {
        compress,
        compressString,
        decompress,
        decompressString,
    } from "https://esm.sh/lzma1@latest";
</script>
```

## 快速启动

六个功能压缩和解压 `.lzma` 格式，三解码 原始数据:

```ts
// For binary data
compress(data: ArrayBuffer | ArrayBufferView, mode?: 1-9 | CompressionOptions): Uint8Array
compressAsync(data: ArrayBuffer | ArrayBufferView, mode?: 1-9 | CompressAsyncOptions): Promise<Uint8Array>
decompress(data: ArrayBuffer | ArrayBufferView, options?: DecompressionOptions): Uint8Array
decompressAsync(data: ArrayBuffer | ArrayBufferView, options?: DecompressAsyncOptions): Promise<Uint8Array>

// For string data
compressString(data: string, mode?: 1-9 | CompressionOptions): Uint8Array
decompressString(data: ArrayBuffer | ArrayBufferView, options?: DecompressionOptions): string

// For raw data without a .lzma header, e.g. from 7z or .xz
decompressRawLzma1(data: ArrayBuffer | ArrayBufferView, options: RawLzma1Options): Uint8Array
decompressRawLzma1Async(data: ArrayBuffer | ArrayBufferView, options: RawLzma1AsyncOptions): Promise<Uint8Array>
decompressRawLzma2(data: ArrayBuffer | ArrayBufferView, options: RawLzma2Options): Uint8Array
```

这个 `Async` 函数返回的字节数与不带 后缀，并可选地等待 `onProgressAsync` 在它们工作的时候回调 调用者可以屈服于事件循环，显示进度或取消。这个 Callback的文档注释中有一个例子。重要：呼叫者可以阅读 `data` 但不得修改它，直到返回的承诺已经解决。

字符串被编码为UTF-8。 `decompressString` 也解码数据压缩 它使用Java的“修改过的UTF-8”。这个 `LZMA` 类 再次从v0.2.0导出；它的 `decompress` 现在返回一个 `Uint8Array`.

### 压缩字符串

```js
import {
    compressString,
    decompressString,
} from "lzma1";

const data = "Hello World!";
const compressed = compressString(data, 1); // level 1 (fastest)
const decompressed = decompressString(compressed);

// data === decompressed
```

### 处理二进制数据

```js
import {
    compress,
    decompress,
} from "lzma1";

const binaryData = new Uint8Array([0x01, 0x02, 0x03, 0x04]);
const compressed = compress(binaryData, 5); // default level
const decompressed = decompress(compressed);
```

### 压缩选项

级别（1-9，默认为5）交易速度大小：

| 水平 | 编码器 | 匹配仪 | 字典 |
| --- | --- | --- | --- |
| 1 | 快 | hc4 | 1 MiB |
| 2 | 快 | hc4 | 2 MiB |
| 3 | 快 | hc4 | 4 MiB |
| 4 | 正常的 | bt4 | 1 MiB |
| 5 | 正常的 | bt4 | 2 MiB |
| 6 | 正常的 | bt4 | 4 MiB |
| 7 | 正常的 | bt4 | 8 MiB |
| 8 | 正常的 | bt4 | 16 MiB |
| 9 | 正常的 | bt4 | 32 MiB |

传递选项而不是关卡。没有给出的选项来自关卡。

```js
const compressed = compress(data, {
    level: 9, // preset 1-9
    dictSize: 1 << 20, // dictionary size in bytes, 4 KiB - 768 MiB
    lc: 3, // literal context bits, 0-4
    lp: 0, // literal position bits, 0-4, lc + lp <= 4
    pb: 2, // position bits, 0-4
    mode: "normal", // "fast" or "normal" (optimal parsing)
    niceLen: 64, // match length that is good enough, 8-273
    matchFinder: "bt4", // "hc4" (hash chain) or "bt4" (binary tree)
    depth: 0, // match finder search depth, 0 = automatic
    endMarker: true, // false omits the end marker, see below
});
```

一个大于输入的字典被缩减到适合它，这节省了内存 压缩和解压缩时。数据与 `lc + lp > 4` 从其他 编码器（例如7-Zip）仍然可以解压缩。

报头保存未压缩的大小，因此数据后面的结束标记是 对于读取它的解码器来说是冗余的。 `endMarker: false` 省略它，比如XZ Java和7-Zip没有 `-eos`，并节省5-6字节，这对于小的很重要 有效载荷，比如QR码。解码器不知道大小需要标记 查找结尾：原始LZMA解码器(`xz --format=raw`, Python的 `FORMAT_RAW`） 报告一个错误或解码到没有它的结束。只有当数据 用它的头(这个库， `xz --format=lzma`（7-Zip）或 大小在其他地方是已知的。知道大小的严格解码器可能会拒绝a 标记，例如XZ表示Java的raw `LZMAInputStream` 构造函数没有 `enableRelaxedEndCondition()`.

### Raw LZMA1和LZMA2

7z档案和 `.xz` 文件存储LZMA数据，没有 `.lzma` Header和keep 它的属性在它们自己的头文件中。将这些属性传递给 `decompressRawLzma1` 或者 `decompressRawLzma2`． 这个库不解析7z 或者 `.xz` 容器。

```js
import {
    decompressRawLzma1,
    decompressRawLzma2,
} from "lzma1";

// A 7z LZMA entry. Its 5-byte coder properties are the byte
// (pb * 5 + lp) * 9 + lc and the dictionary size, 32-bit little-endian.
const file = decompressRawLzma1(packed, {
    lc: 3, // literal context bits, 0-8
    lp: 0, // literal position bits, 0-4
    pb: 2, // position bits, 0-4
    dictSize: 1 << 24, // dictionary size in bytes
    uncompressedSize: 123_456, // optional, the size from the 7z header
    memoryLimitKb: 65_536, // optional
});

// LZMA2 data from a 7z entry or an .xz block
const block = decompressRawLzma2(packed, {
    dictSize: 1 << 20, // from the LZMA2 properties byte, see "LZMA2" below
    memoryLimitKb: 65_536, // optional
});
```

LZMA2标记自己的末端，不需要大小。Raw LZMA1需要未压缩的 大小或结束标记。7-Zip写无止境 默认情况下，标记，所以从7z头传递大小。 `xz --format=raw --lzma1` 总是写一个。对于已知的大小，数据必须 在那里结束，有或没有结束标记，如with `decompress`． 结束标记 在此之前，大小是一个错误，如 `strict`.

字典大小来自容器，以及损坏或恶意的头文件 最高可申领4gib。 `memoryLimitKb` 就像Java的XZ一样 `memoryLimit`. 解码器根据字典大小估算其在KiB中的内存 `lc` 和 `lp` 对于LZMA1，并抛出 `MemoryLimitError` 在它分配任何东西之前 估价超出了限额。错误的 `memoryNeededKb` 和 `memoryLimitKb` 字段持有 两个数字。估计值按给定的大小计算字典。这个 字典缓冲区最多从64kib开始，只有在输出到达时才翻倍， 因此，在输出增加之前，一个巨大的声称字典不需要任何成本。已知的LZMA1 大小改变了这一点： `decompressRawLzma1` 然后一次分配最多64个MiB 对于字典或输出，它为 `decompress` 尺寸在吗 这个 `.lzma` 头。估计不包括输出。

### 流

`Compress` 和 `Decompress` 是 `TransformStream`S，像内置的一样使用 `CompressionStream`：

```js
import {
    Compress,
    Decompress,
} from "lzma1";

// Compress a file
const compressed = file.stream().pipeThrough(new Compress(5));

// Decompress a download
const response = await fetch("/data.lzma");
const text = await new Response(response.body.pipeThrough(new Decompress())).text();
```

流的大小是事先不知道的，所以标头将其标记为未知和 数据总是以结束标记结束： `new Compress({ endMarker: false })` 抛出一个 `RangeError`.

`DecompressRawLzma1` 和 `DecompressRawLzma2` 解码流中的原始数据和 采用与函数相同的选项。无效选项和字典结束 从构造函数抛出内存限制。

```js
const output = response.body.pipeThrough(new DecompressRawLzma2({ dictSize: 1 << 20 }));
```

在TypeScript中，它们的类型需要 `TransformStream` 从 `DOM` 自由或 `@types/node` (或 `skipLibCheck`）。

### 错误

解压缩被截断或损坏的数据会抛出 `Error`,如。 `"Truncated input"` 或者 `"Corrupted input: match distance is too large"`. 这个 `.lzma` 格式没有校验和，所以一些损坏的数据解码没有 输出错误。原始LZMA1和LZMA2数据也没有；7 z 和 `.xz` 将校验和保存在容器中。 无效选项引发 `RangeError`，还有一本字典 `memoryLimitKb` 抛出一个 `MemoryLimitError`.

数据必须以标题中的大小结束，带或不带结束标记 在它之后。在该大小之前的结束标记也结束了数据，因为有些 制作人写的大小太大了。 `strict` 拒绝它，如XZ表示Java xz做：

```js
decompress(data, { strict: true });
new Decompress({ strict: true });
```

在解压缩来自不可信源的数据时， `maxOutputLength` 可以保护 对抗“解压炸弹”攻击，在这种攻击中，几个字节的精心制作的数据会扩展 g。对于除原始LZMA2之外的每个解码器，它以字节为单位限制输出。 与 `strict`对于原始LZMA1，较大的声明大小会抛出错误 `OutputLimitError` 在分配任何东西之前。否则，与未知一样 大小，解码抛出一个一旦输出超过限制，因为一个结束标记 仍然可以结束其中的数据：

```js
decompress(data, { maxOutputLength: 1_000_000 });
```

### HTML例子

```html
<!DOCTYPE html>
<html>
    <body>
        <textarea id="input">Hello World!</textarea><br />
        <button id="run">Compress & Decompress</button>
        <div id="result"></div>

        <script type="module">
            import { compressString, decompressString } from "https://esm.sh/lzma1@latest";

            document.getElementById("run").onclick = () => {
                const text = document.getElementById("input").value;
                const compressed = compressString(text);
                const decompressed = decompressString(compressed);

                document.getElementById("result").innerHTML =
                    `Original: ${text.length} bytes<br>` +
                    `Compressed: ${compressed.length} bytes<br>` +
                    `Result: ${decompressed}`;
            };
        </script>
    </body>
</html>
```

## 它是如何工作的

LZMA （Lempel-Ziv-Markov chain Algorithm）是一种压缩算法 将字典（lz77风格）压缩器与范围编码器相结合。它是已知的 因为它的高压缩比和在7z和xz格式中使用。

### LZMA头

这个 `.lzma` 数据以一个13字节的头开始，后面跟着压缩数据：

```mermaid
packet-beta
  0-7: "Properties (lc, lp, pb)"
  8-39: "Dictionary Size (32-bit, LE)"
  40-103: "Uncompressed Size (64-bit, LE)"
```

第一个字节是 `(pb * 5 + lp) * 9 + lc`． 所有的未压缩大小 `0xFF` 字节表示未知。更多的 [信息](https://docs.fileformat.com/compression/lzma/#lzma-header) 关于LZMA报头 结构。

### LZMA2

LZMA2将数据分成未压缩的2 MiB和64 KiB的块 压缩。每个块都以一个控制字节开始：

| 控制 | 块 |
| --- | --- |
| 0 x00 | 数据结束 |
| 0 x01 | 未压缩，重置字典 |
| 0 x02 | 未压缩的 |
| 0 x80-0x9f | LZMA |
| 0 xa0-0xbf | LZMA，重置状态 |
| 0 xc0-0xdf | LZMA，重置状态，new `lc`/`lp`/`pb` |
| 0 xe0-0xff | LZMA，重置字典和状态，new `lc`/`lp`/`pb` |

在接下来的2个字节中，未压缩的块的大小为- 1。一个LZMA Chunk有这样的头，大小为- 1，大端序：

```mermaid
packet-beta
  0-7: "Control (low 5 bits: size bits 16-20)"
  8-23: "Uncompressed size, bits 0-15"
  24-39: "Compressed size"
  40-47: "Properties (0xC0 and up)"
```

第一个块必须重置字典，并且 `lc + lp` 不能超过4。 7 z和 `.xz` 将字典大小存储为一个字节 `n`． 尺寸是 `0xFFFFFFFF` 用于 `n = 40` 和 `(2 | (n & 1)) * 2 ** ((n >> 1) + 11)` 下面 从4千磅起。

### 基准

看到 [文档/ benchmarks.md](https://npmcn.com/package/%40cjser/lzma1/docs/benchmarks.md), [板凳上](https://npmcn.com/package/%40cjser/lzma1/bench) 来运行它们。

## 验证

编码器的输出字节与 [XZ代表Java](https://github.com/tukaani-project/xz-java) 在提交 [`6925f81`](https://github.com/tukaani-project/xz-java/commit/6925f81244a99d0ea4f3fd021938e2ee1e6de2eb) 输入和编码器设置的语料库。解码器处理一组 除了两种已记录的腐化类型之外，腐化流的方式相同 它接受的输入，而Java的XZ拒绝它们。原始的LZMA1和LZMA2 解码器处理它们自己的一组流，就像Java的XZ一样。CI检查 所有三个。 [设备/ README.md](https://npmcn.com/package/%40cjser/lzma1/fixtures/README.md) 描述语料库以及如何 重新生成它。

对于这个代码来说，通过测试是不够的。不同于的编码器决策 Java的XZ通常仍然产生正确解压缩的有效流， 因此，往返测试忽略了它，代码虽然很小，但具有巨大的输入 空间中，许多边缘情况和模算法可以将这些差异隐藏在其中。 所以对编码员的每一次更改都有一个书面的参数 [文档/ verification.md](https://npmcn.com/package/%40cjser/lzma1/docs/verification.md)要么这种行为没有改变 对于所有输入，或者对Java代码的文档化偏离。身份测试 在语料库中检查这些参数。

自己检查： `bun test src/xz-java-identity_test.ts`，或者 `node fixtures/verify.ts` （节点>= 22.18）在V8上运行它们。

## 相关

-   [XZ代表Java](https://github.com/tukaani-project/xz-java) -移植这个库的实现
-   [LZMA SDK](https://www.7-zip.org/sdk.html) - Igor Pavlov的参考实现
-   [XZ跑龙套](https://github.com/tukaani-project/xz) - `xz` 和liblzma
-   [LZMA-JS](https://github.com/LZMA-JS/LZMA-JS) -原始的JavaScript实现
-   [lzma-purejs](https://github.com/cscott/lzma-purejs)
-   [lzmajs](https://github.com/glinscott/lzmajs)

## cjser

这个包是由cjser为仍然需要的项目生成的commonjs兼容的构建 `require()` 支持。源版本与原始的npm包版本匹配，对这个生成的构建带有cjser预发布后缀。 原始存储库: [https://github.com/xseman/lzma1](https://github.com/xseman/lzma1)

## 常见问题

### @cjser/lzma1 是什么？

一个JavaScript实现的Lempel-Ziv-Markov （LZMA）链压缩算法

### 如何安装 @cjser/lzma1？

在项目目录运行 npm install @cjser/lzma1，或使用 pnpm add / yarn add / bun add。

### @cjser/lzma1 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @cjser/lzma1 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @cjser/lzma1 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=18\.0\.0。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @cjser/lzma1 可以商用吗？

@cjser/lzma1 使用 Apache-2\.0 许可。宽松许可：允许商业使用、修改和再分发，并附带明确的专利授权；分发时需保留许可与 NOTICE 文件，修改过的文件要注明改动。以上为概括，不构成法律意见，请以许可原文为准。

### @cjser/lzma1 还在维护吗？

最新版本 0\.6\.3-cjser\.2 发布于 2026/11/01（2 天前）；至今共发布 6 个版本，其中过去 12 个月发布了 6 个；首次发布于 2026/05/07。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

