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
相关产品推荐
相关产品推荐

