You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Archiver npm包压缩单个文件无响应 调用相关方法未生成压缩包如何解决

问题根因

  1. 缺少输出流错误监听
    你仅对archiver实例添加了错误监听,但fs.createWriteStream生成的输出流没有配置错误回调。如果输出zip的父目录不存在、没有写入权限,输出流会直接抛出错误但无法被捕获,最终导致流程卡住,既不会生成压缩包也不会触发结束回调。
  2. API调用混淆
    archive.file()方法第一个参数仅接受本地文件路径字符串,你之前尝试传入可读流的用法是错误的,传入流需要改用archive.append()方法。
  3. 单文件判断逻辑不严谨
    依靠后缀长度判断是否为单文件的逻辑缺陷很大,.docx、.xlsx这类长度超过4的后缀会被误判为目录,无后缀的文件也会被错误归类。
  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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 20:45:05