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

Node.js中basic-ftp模块目录创建失败且文件上传条目丢失无报错求助

问题排查与解决方案

看起来你的代码主要有三个核心问题导致部分条目被跳过且无报错,我们一步步拆解:

1. 路径处理逻辑错误

你之前的代码中,通过fileArray.splice(1)处理路径时,错误地丢弃了路径的顶层部分(比如src/SuperBlog/...中的src):

  • 对于目录条目(如src/),fileArray.splice(1)返回空数组,导致你执行ensureDir("")——这相当于在根目录重复操作,根本没创建src目录;
  • 对于文件条目(如src/SuperBlog/Model/Article.php),最终生成的上传路径是SuperBlog/Model/Article.php,丢失了src前缀,而因为父目录SuperBlog/Model不存在,basic-ftp会静默上传失败(默认不会自动创建父目录)。

2. Zip条目流未被正确消耗

使用unzipper.Parse()时,每个entry都是一个可读流。如果流没有被完全消耗(比如目录条目不需要上传,但你没处理它的流),unzipper会卡住,无法继续解析后续的zip条目,这就是为什么你的循环提前终止,只处理了前面几个文件和目录。

3. 缺少异常捕获机制

你的代码没有添加try-catch块,即使上传或目录创建失败,错误也会被静默忽略,导致你完全看不到问题出在哪里。


修正后的代码

const unzipper = require("unzipper");
const ftp = require("basic-ftp");
const fs = require("fs");
const path = require("path");

const client = new ftp.Client();
try {
  await client.access({...options});
  // 切换到FTP根目录一次即可,无需每次循环重复执行
  await client.cd("/");

  const zipStream = fs.createReadStream(path.join(filePath, `code.zip`))
    .pipe(unzipper.Parse({ raw: true, forceStream: true }));

  for await (const entry of zipStream) {
    const entryPath = entry.path;
    const entryType = entry.type;

    try {
      if (entryType === 'File') {
        console.log(`Uploading file: ${entryPath}`);
        // 直接使用zip内的完整路径上传
        await client.uploadFrom(entry, entryPath);
      } else if (entryType === 'Directory') {
        console.log(`Creating directory: ${entryPath}`);
        // 创建zip内对应的目录
        await client.ensureDir(entryPath);
        // 目录条目无需上传,必须调用autodrain消耗流
        entry.autodrain();
      } else {
        // 处理符号链接等其他类型的条目,直接消耗流跳过
        console.log(`Skipping unsupported entry type ${entryType}: ${entryPath}`);
        entry.autodrain();
      }
    } catch (err) {
      console.error(`Failed to process ${entryPath}:`, err.message);
      // 即使出错也要消耗流,避免unzipper卡住
      entry.autodrain();
    }
  }
  console.log("Entry Read Finished");
} catch (ftpErr) {
  console.error("FTP connection or initialization failed:", ftpErr.message);
} finally {
  // 确保FTP客户端最终关闭
  client.close();
}

关键改进点说明

  • 路径处理:直接使用zip条目的原生entry.path,保证目录和文件路径完全匹配预期;
  • 流处理:对所有非文件条目调用entry.autodrain(),确保unzipper能继续解析后续内容;
  • 异常捕获:添加两层try-catch,分别捕获FTP连接错误和单个条目处理错误,方便排查问题;
  • 资源清理:使用finally块确保FTP客户端最终关闭,避免资源泄漏。

如果之前使用jsFtp也遇到类似问题,大概率也是流未正确消耗或路径处理错误导致的,你可以用类似的思路去调整代码。

内容的提问来源于stack exchange,提问作者sp_kolinfure

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 22:32:41