使用Archiver npm包压缩单个文件无响应 调用相关方法未生成压缩包如何解决
问题根因
- 缺少输出流错误监听
你仅对archiver实例添加了错误监听,但fs.createWriteStream生成的输出流没有配置错误回调。如果输出zip的父目录不存在、没有写入权限,输出流会直接抛出错误但无法被捕获,最终导致流程卡住,既不会生成压缩包也不会触发结束回调。 - API调用混淆
archive.file()方法第一个参数仅接受本地文件路径字符串,你之前尝试传入可读流的用法是错误的,传入流需要改用archive.append()方法。 - 单文件判断逻辑不严谨
依靠后缀长度判断是否为单文件的逻辑缺陷很大,.docx、.xlsx这类长度超过4的后缀会被误判为目录,无后缀的文件也会被错误归类。 - 异步逻辑未正确封装
函数声明为async但内部没有等待压缩流程完成就直接返回路径,此时压缩包还未生成完成,后续逻辑如果立即使用该路径会出现异常。
修复方案
- 输出流创建前先判断父目录是否存在,不存在则提前创建
- 给输出流添加错误监听,及时捕获写入异常
- 改用
fs.stat判断传入路径是文件还是目录,替代后缀判断逻辑 - 将整个压缩流程封装为Promise,压缩完成后再返回结果
修正后完整代码
const fs = require('fs'); const archiver = require('archiver'); const path = require('path'); const s4 = require('../testcli/s4'); module.exports = async function zipper(user, pass, orgid, s4url, apiToken, newOrgName, file) { let parentDirect; const resolvedPath = path.resolve(file); // 先判断是文件还是目录 const stat = await fs.promises.stat(resolvedPath); const isFile = stat.isFile(); if(file == "./"){ parentDirect = ".."; }else{ parentDirect = path.dirname(resolvedPath); } const newZipFile = path.join(parentDirect, 's4.zip'); // 确保输出目录存在 await fs.promises.mkdir(parentDirect, { recursive: true }); var folderName = file; // 原无限循环判断逻辑保留 if(path.resolve(parentDirect).length > path.resolve(folderName).length){ console.log(folderName.search(parentDirect)); console.error('\x1b[36m%s\x1b[0m', 'ERROR!!!! : Please adjust where your console is pointed, this will result in an infinite loop. Exiting.'); return; } var P = ['\\', '|', '/', '-']; var x = 0; let scansdisplayinterval; return new Promise((resolve, reject) => { var output = fs.createWriteStream(newZipFile); var archive = archiver('zip'); scansdisplayinterval = setInterval(function () { twrl(); }, 250); // 输出流完成事件 output.on('close', function () { console.log('\x1b[36m%s\x1b[0m', archive.pointer() + ' total bytes'); console.log('\x1b[36m%s\x1b[0m', 'archiver has been finalized and the output file descriptor has closed.'); try { process.stdout.write(newZipFile); clearInterval(scansdisplayinterval); s4(user, pass, newZipFile, orgid, s4url, apiToken, newOrgName); resolve(newZipFile); } catch (e) { reject(e); } }); // 新增输出流错误监听 output.on('error', function (err) { clearInterval(scansdisplayinterval); reject(err); }); archive.on('error', function (err) { clearInterval(scansdisplayinterval); reject(err); }); archive.on('warning', function(err) { clearInterval(scansdisplayinterval); reject(err); }); output.on('end', function() { console.log('\x1b[36m%s\x1b[0m', 'Data has been drained'); }); archive.pipe(output); if(isFile){ // 单文件逻辑,用file方法传路径即可 console.log('singleFile', resolvedPath); archive.file(resolvedPath, { name: path.basename(resolvedPath) }); // 如果要传流用append: // archive.append(fs.createReadStream(resolvedPath), {name: path.basename(resolvedPath)}); }else{ archive.directory(folderName, false); } console.log('\x1b[36m%s\x1b[0m', "Zipping: " + folderName + " To: " + newZipFile); console.log('\x1b[36m%s\x1b[0m', "Zipping To: " + path.resolve(newZipFile)); archive.finalize(); function twrl() { process.stdout.write('\rZipping ... ' + P[x++]); x &= 3; } }) };
内容的提问来源于stack exchange,提问作者The Traveling Coder
相关产品推荐
相关产品推荐

