ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

JSZip nodeStream() 详解:在 Node.js 中将 ZIP 内文件内容转为 Streams3 可读流

JSZip nodeStream() 详解:在 Node.js 中将 ZIP 内文件内容转为 Streams3 可读流 开发工具【免费下载链接】jszipCreate, read and edit .zip files with Javascript项目地址https://gitcode.com/gh_mirrors/js/jszip点击查看免费下载导读nodeStream()是 JSZip 中ZipObject即zip.file(...)返回的对象提供的方法之一用于把 ZIP 归档中某个文件的内容转换为 Node.js 标准的 Streams3 可读流从而支持pipe()、背压backpressure处理等流式编程模式。该方法仅适用于 Node.js 环境需要Buffer与readable-stream支持是 JSZip 面向服务端场景如把大文件从 ZIP 中解压写盘、经 HTTP 响应流式下发、或交给下游管道处理的核心接口之一。读完本文你将掌握nodeStream()的参数语义、onUpdate进度回调的元数据结构、底层 worker 到 Node 流的适配原理以及如何在实战中正确使用并规避常见坑。方法签名与返回类型nodeStream(type[, onUpdate])返回一个 Node.js Streams3 规范的可读流内容是所请求类型的文件数据。参数类型默认值说明typeStringnodebuffer目前仅支持nodebufferonUpdateFunction可选每次内部数据块更新时被调用携带进度元数据返回值为一个遵循 Streams3 语义的 Node.js 可读流具体实现为NodejsStreamOutputAdapter见下文源码分析。onUpdate回调的metadata结构与async()的 onUpdate 回调 完全一致详见后文。与 async() / internalStream() 的关系在深入细节之前先厘清ZipObject上三个输出方法的定位这有助于理解nodeStream()的设计取舍方法返回适用场景async(type[, onUpdate])Promise一次性把整个文件内容累积成完整结果字符串、Uint8Array、Buffer等适合中小文件internalStream(type)StreamHelperJSZip 内部统一的、与运行环境无关的流封装见 internalStream 文档需要手动监听data/error/end事件nodeStream(type[, onUpdate])Node.js 可读流直接得到 Node 生态的标准流对象可pipe()到文件、网络或任意 writable 流从 lib/zipObject.js 的源码可以看到三者的实现关系async: function (type, onUpdate) { return this.internalStream(type).accumulate(onUpdate); }, nodeStream: function (type, onUpdate) { return this.internalStream(type || nodebuffer).toNodejsStream(onUpdate); }也就是说nodeStream()本质上是internalStream()的流式输出变体——它先构造一个内部StreamHelper内部类型强制为nodebuffer再通过StreamHelper#toNodejsStream()将其包装成 Node.js 可读流。区别在于async()会通过accumulate()把所有 chunk 收拢成单个完整值而nodeStream()则让数据以 chunk 形式持续流出不需要等全部内容解压完从而显著降低峰值内存占用。参数详解type目前仅支持nodebuffer与async()支持的八种类型base64、text/string、binarystring、array、uint8array、arraybuffer、blob、nodebuffer不同nodeStream()目前只支持nodebuffer。这一点在 lib/stream/StreamHelper.js 的toNodejsStream()中有硬性校验toNodejsStream : function (updateCb) { utils.checkSupport(nodestream); if (this._outputType ! nodebuffer) { // an object stream containing blob/arraybuffer/uint8array/string // is strange and I dont know if it would be useful. // I you find this comment and have a good usecase, please open a // bug report ! throw new Error(this._outputType is not supported by this method); } return new NodejsStreamOutputAdapter(this, { objectMode : this._outputType ! nodebuffer }, updateCb); }源码注释也说明了原因一个输出blob/arraybuffer/uint8array/string的对象流object stream语义怪异且用途不明因此目前一律拒绝。调用nodeStream(string)之类会直接抛出Error。所以省略type时默认值为nodebuffertype || nodebuffer显式传入nodebuffer与省略效果一致传入其他任何值都会在toNodejsStream()阶段抛错。另外需要注意运行环境nodebuffer输出依赖全局Buffernodestream支持依赖readable-stream这两项在 lib/support.js 与 lib/support.js 中分别检测在纯浏览器环境如用 browserify/webpack 打包且未注入Buffer下调用会失败。onUpdate进度回调onUpdate是可选函数在内部每个数据块chunk被推送到输出流时调用参数为metadata对象结构与 async() 的 onUpdate 回调 完全一致元数据字段类型说明percentnumber完成百分比0 到 100 之间的浮点数典型用法与async()中完全相同的写法zip.file(big_file.bin).nodeStream(nodebuffer, function updateCallback(metadata) { console.log(progression: metadata.percent.toFixed(2) %); }).pipe(fs.createWriteStream(/tmp/big_file.bin));注意percent是基于解压/输出过程中的 chunk 计数得出的估算值在流输入场景下元数据固定为percent: 0见下文源码说明并非字节级的精确比例适合用于展示粗粒度进度条。官方示例流式解压写盘文档给出了一个完整的 Node.js 实战示例——把 ZIP 中名为my_text.txt的文件流式解压并写入本地文件系统zip .file(my_text.txt) .nodeStream() .pipe(fs.createWriteStream(/tmp/my_text.txt)) .on(finish, function () { // JSZip generates a readable stream with a end event, // but is piped here in a writable stream which emits a finish event. console.log(text file written.); });要点拆解zip.file(my_text.txt)返回对应的ZipObject.nodeStream()使用默认typenodebuffer返回可读流.pipe(fs.createWriteStream(...))将解压后的字节写入磁盘finish事件由目标 writable 流fs.createWriteStream在全部数据写入完成后触发——这正是示例注释强调的JSZip 生成的是可读流其完成事件是end而管道下游的 writable 流在 flush 完成后发出的是finish事件。若想监听可读流一侧则应监听end事件。这个模式天然具备背压backpressure处理能力当pipe的目标写入速度跟不上时可读流会暂停向消费者推送数据内存占用可控适合处理大文件。底层原理从 Worker 到 Node 流的适配nodeStream()的整个链路涉及三层组件从源码可以看出完整的数据流转ZipObject#nodeStream() └─ internalStream(nodebuffer) // lib/zipObject.js#L39-L66 ├─ _decompressWorker() // 解压 worker ├─ Utf8Encode/DecodeWorker // 按需做 UTF-8 编解码 └─ new StreamHelper(worker, nodebuffer, ) └─ StreamHelper#toNodejsStream() // lib/stream/StreamHelper.js#L197 └─ new NodejsStreamOutputAdapter(helper, {objectMode: false}, onUpdate)1.internalStream()产出内部 worker 流lib/zipObject.js 中internalStream(type)负责把ZipObject持有的数据可能是CompressedObject、GenericWorker或普通原始数据变成解压 worker 链并按需插入Utf8EncodeWorker/Utf8DecodeWorker当二进制标记与请求类型不一致时进行编码转换最后包装成StreamHelper。_decompressWorker()lib/zipObject.js按数据类型分派数据是CompressedObject调用getContentWorker()得到解压 worker数据本身是GenericWorker直接复用例如通过流写入的文件其他原始数据包一层DataWorker。2.NodejsStreamOutputAdapter把 worker 事件翻译成 Node 流事件真正的 Node 流适配在 lib/nodejs/NodejsStreamOutputAdapter.js 中实现。它继承自readable-stream的Readable把StreamHelper的data/error/end事件映射为 Node 流语义function NodejsStreamOutputAdapter(helper, options, updateCb) { Readable.call(this, options); this._helper helper; var self this; helper.on(data, function (data, meta) { if (!self.push(data)) { self._helper.pause(); // 背压内部缓冲区满时暂停上游 } if(updateCb) { updateCb(meta); // 进度回调 } }) .on(error, function(e) { self.emit(error, e); }) .on(end, function () { self.push(null); // 通知消费者流结束 }); } NodejsStreamOutputAdapter.prototype._read function() { this._helper.resume(); // 消费者请求更多数据时恢复上游 };这里体现了 Streams3 的背压闭环消费者通过_read()表示“我要更多数据”适配器随即resume()内部 helperhelper 的data事件把 chunk 交给self.push(data)若返回false内部缓冲区已满立即pause()上游 worker阻止数据继续产生全部数据处理完后end事件触发self.push(null)可读流正常结束。值得注意的是readable-stream的选择JSZip 在 lib/nodejs/NodejsStreamOutputAdapter.js 中直接require(readable-stream)以屏蔽不同 Node 版本间的 stream 实现差异而在浏览器打包场景lib/readable-stream-browser.js 注释说明 bundler 通常会把streamshim 解析到该文件最终module.exports require(stream)保证同一份代码在 Node 与浏览器带 shim下行为一致。3. 环境支持检测lib/support.js 在加载时尝试require(readable-stream)成功则support.nodestream trueStreamHelper也据此在support.nodestream为真时才尝试加载NodejsStreamOutputAdapterlib/stream/StreamHelper.js。因此在没有readable-stream的环境中调用nodeStream()会得到明确的“不支持”错误而不是静默失败。测试验证行为约定测试文件 test/asserts/stream.js 覆盖了nodeStream()的关键行为约定可作为使用时的参考默认与显式 type 等价nodeStream()与nodeStream(nodebuffer)都能生成可工作的流stream.js流式解压正确性对 ZIP 内的文本与二进制文件如Hello.txt、images/smile.gif通过nodeStream()读取并与原始内容比对一次性消费限制包含流的ZipObject无法被nodeStream()读取两次stream.js——底层 worker 链只可被消费一次这一点与普通数据不同错误传播数据损坏或类型不支持时nodeStream()会在可读流上发出error事件stream.js。版本历史也可佐证其演进JSZip 在 3.x 早期版本开始支持 nodejs streams同时用于file()输入与generateAsync()输出见 CHANGES.md随后 TypeScript 类型定义也修正了nodeStream的返回类型CHANGES.md。实战建议与注意事项综合文档、源码与测试使用nodeStream()时有几点值得注意只传nodebuffer或省略任何其他type都会抛Error。若需要字符串、Uint8Array、base64等输出请改用async(type)。务必监听错误解压失败、CRC 校验失败等错误会以error事件形式在可读流上发出未监听error的流在 Node.js 中会导致进程级异常。区分end与finish可读流侧用endpipe后的 writable 流侧用finish官方示例即此场景。流只能消费一次如果ZipObject的数据来自流输入nodeStream()第二次调用将失败即使来自普通数据重复消费也不符合流的一次性语义建议为每次输出重新从zip.file(...)获取对象。适用于大文件/低内存场景相比async()的全量累积nodeStream()边解压边输出并配合背压是处理大体积单文件或内存敏感场景的推荐路径配合generateNodeStream()可在服务端实现 ZIP 的流式读写闭环。仅限 Node 环境浏览器端请使用async(uint8array)或async(blob)如需在浏览器侧做流式处理可评估internalStream()与 StreamHelper 的能力边界。参考链接nodeStream() API 文档async() API 文档type 选项与 onUpdate 元数据internalStream() API 文档ZipObject 实现nodeStream / async / internalStreamStreamHelper 实现toNodejsStream / accumulateNodejsStreamOutputAdapter 实现NodejsStreamInputAdapter 实现流式写入入口support.js 环境检测相关测试用例赞分享开发工具【免费下载链接】jszipCreate, read and edit .zip files with Javascript项目地址https://gitcode.com/gh_mirrors/js/jszip点击查看免费下载相关推荐JSZip ZipObject.internalStream() 深入解析以 StreamHelper 流式读取 zip 条目内容JSZip ZipObject.internalStream 深入解析以 StreamHelper 流式读取 zip 条目内容 导读 ZipObject.in开发工具pointnet.pytorch可视化技巧3D点云结果展示与性能分析pointnet.pytorch可视化技巧3D点云结果展示与性能分析 pointnet.pytorch是一个基于PyTorch实现的3D点云深度学习框架专注人工智能深度学习计算机视觉Cipher.so完全配置指南从Gradle集成到Java调用的全流程Cipher.so完全配置指南从Gradle集成到Java调用的全流程 Cipher.so是一个创新的Android安全解决方案它通过将敏感数据加密存储在原上一篇Turborepo × GitHub Actions 完整接入指南工作流、包管理器、远程缓存与 --affected 增量构建下一篇TensorRT Model Optimizer常见问题解答新手必知的10个关键知识点创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表