如何使用Node.js内置zlib模块从zip压缩包中提取单个指定文件
实现前提说明
Node.js 内置的 zlib 模块仅负责处理原始的 deflate/gzip 压缩数据流,本身不包含 ZIP 归档格式的文件结构解析能力。ZIP 是归档+压缩结合的格式,包含文件头、元数据、校验值等额外结构,所以我们需要手动解析 ZIP 结构筛选目标文件,再调用 zlib 解压对应数据段即可。
完整实现代码
const fs = require('fs'); const zlib = require('zlib'); // 本地文件头签名,ZIP规范固定值 const LOCAL_FILE_HEADER_SIGNATURE = 0x04034b50; // 压缩方法:deflate对应值8,未压缩对应0 const COMPRESSION_METHOD_DEFLATE = 8; async function extractTest1FromZip() { // 读取整个zip文件到buffer const zipBuffer = await fs.promises.readFile('./test.zip'); let offset = 0; while (offset < zipBuffer.length - 4) { // 读取当前块的签名 const signature = zipBuffer.readUInt32LE(offset); // 读到目录头就终止遍历,所有本地文件都在目录头之前 if (signature === 0x02014b50) break; if (signature !== LOCAL_FILE_HEADER_SIGNATURE) { offset += 1; continue; } // 解析本地文件头固定字段,对应ZIP规范偏移 const compressionMethod = zipBuffer.readUInt16LE(offset + 8); const compressedSize = zipBuffer.readUInt32LE(offset + 18); const uncompressedSize = zipBuffer.readUInt32LE(offset + 22); const fileNameLength = zipBuffer.readUInt16LE(offset + 26); const extraFieldLength = zipBuffer.readUInt16LE(offset + 28); // 读取文件名 const fileName = zipBuffer.toString('utf8', offset + 30, offset + 30 + fileNameLength); // 匹配到目标文件 if (fileName === 'test1.txt') { // 计算压缩数据的起始偏移 const dataOffset = offset + 30 + fileNameLength + extraFieldLength; // 截取压缩数据段 const compressedData = zipBuffer.subarray(dataOffset, dataOffset + compressedSize); // 解压数据,zip的deflate数据无zlib头,所以用inflateRaw const uncompressedData = compressionMethod === COMPRESSION_METHOD_DEFLATE ? zlib.inflateRawSync(compressedData) : compressedData; // 写入解压后的文件 await fs.promises.writeFile('./test1.txt', uncompressedData); console.log('test1.txt 提取成功'); return; } // 跳过当前文件的整个块,处理下一个文件 offset += 30 + fileNameLength + extraFieldLength + compressedSize; } console.log('未找到目标文件 test1.txt'); } extractTest1FromZip().catch(err => console.error('提取失败:', err));
注意事项
- 上述实现仅适配无加密、使用标准deflate压缩、无分片的常规ZIP包,足够覆盖绝大多数普通使用场景
- 实现完全依赖Node.js内置模块,不需要安装任何第三方依赖
内容的提问来源于stack exchange,提问作者Moin Ahmad Ansari
相关产品推荐
相关产品推荐

