类:zlib.ZipFile
🌐 Class: zlib.ZipFile
ZIP 压缩档案 API 是实验性的。第一次使用它的任何部分(包括这个类)都会发出实验性警告;仅仅导入 node:zlib 不会。
🌐 The ZIP archive API is experimental. Using any part of it (this class among
them) emits an experimental warning the first time; merely importing
node:zlib does not.
对磁盘上 ZIP 压缩包条目的随机访问视图。只会预先读取压缩包的尾部和中央目录;成员内容则按需从磁盘懒加载。当使用 { writable: true } 打开时可写:zipFile.addEntry()/zipFile.add() 会在中央目录原来的位置追加新成员的数据,然后紧接着重写中央目录;zipFile.delete() 则只重写中央目录。两者都意味着方法返回的 Promise 一旦完成,文件就被修改了。被删除或替换的成员会留下空闲空间;zipFile.compact() 会生成一个没有这些空闲空间的流。
🌐 A random-access view over the entries of a ZIP archive on disk. Only the
archive's tail and central directory are read up front; member content is
read from disk lazily, on demand. Writable when opened with
{ writable: true }: zipFile.addEntry()/zipFile.add() append the
new member's data where the central directory used to be, then rewrite the
central directory immediately after it; zipFile.delete() just rewrites
the central directory. Both mean the file is altered as soon as the method's
returned Promise fulfills. Deleted or replaced members are left behind as
dead space; zipFile.compact() produces a stream with none.
这些就地编辑 不是崩溃原子性的。中央目录是就地重写的,所以如果写入过程中失败——比如磁盘满了、设备断开、进程被杀掉——可能会导致磁盘上的归档文件只写了一半或者中央目录丢失,也就是说无法读取,尽管之前的成员数据是完整的。被拒绝的调用会显示底层错误,而且 ZipFile 对象仍然可用(它的内存视图不会被丢弃,所以调用者可以尝试恢复——比如用 zipFile.compact() 在其他地方重新写入条目),但这个内存视图可能已经和磁盘上的字节不匹配。如果需要在失败情况下保持数据可靠性,应该写入副本,或者用 compact() 写入一个新文件。
🌐 These in-place edits are not crash-atomic. Rewriting the central directory
happens in place, so a write that fails partway - the disk fills, the device
disconnects, the process is killed - can leave the archive on disk with a
partial or missing central directory, i.e. unreadable, even though the member
data before it is intact. The rejected call surfaces the underlying error and
the ZipFile object is left usable (its in-memory view is not discarded, so a
caller can attempt recovery - for example re-writing the entries elsewhere with
zipFile.compact()), but that in-memory view may no longer match the bytes
on disk. Write to a copy, or compact() into a fresh file, when durability
across a failure matters.
每个方法都有一个 *Sync 对应的版本。和同步的 node:fs API 一样,这些方法会阻塞 Node.js 的事件循环和后续的 JavaScript 执行,直到操作完成;只在需要同步执行的情况下使用它们(例如短生命周期脚本或启动代码),不要在必须保持响应的代码中使用。如果在同一个 ZipFile 上的异步 add()、addEntry()、delete() 或 close() 还没有完成时调用同步方法,它会抛出 ERR_INVALID_STATE,因为让两者交错执行可能会破坏存档。
🌐 Every method has a *Sync counterpart. As with the synchronous node:fs
APIs, these block the Node.js event loop and further JavaScript execution
until the operation completes; use them only where synchronous execution is
appropriate (for example, short-lived scripts or startup code), not in code
that must stay responsive. A synchronous method throws ERR_INVALID_STATE
if called while an asynchronous add(), addEntry(), delete(), or
close() on the same ZipFile has not settled yet, since letting the two
interleave could corrupt the archive.
import { ZipFile } from 'node:zlib';
import { Buffer } from 'node:buffer';
const zip = await ZipFile.open('archive.zip', { writable: true });
try {
const entry = await zip.get('member.txt');
console.log((await entry.content()).toString());
for await (const chunk of await zip.stream('huge.bin')) {
// Process each chunk without buffering the whole member.
}
await zip.add('new.txt', Buffer.from('hello'));
await zip.delete('unwanted.txt');
} finally {
await zip.close();
}const { ZipFile } = require('node:zlib');
async function main() {
const zip = await ZipFile.open('archive.zip', { writable: true });
try {
const entry = await zip.get('member.txt');
console.log((await entry.content()).toString());
for await (const chunk of await zip.stream('huge.bin')) {
// Process each chunk without buffering the whole member.
}
await zip.add('new.txt', Buffer.from('hello'));
await zip.delete('unwanted.txt');
} finally {
await zip.close();
}
}
main();