Node-FTP实现断点续传下载后文件大小正常但损坏问题
FTP下载断点续传后ZIP文件损坏修复方案
问题根因
你当前使用r+文件写入标志配合FTP restart方法的用法存在逻辑缺陷,这是文件损坏的直接原因:
r+模式打开文件时不会自动截断文件内容,如果上次下载中途异常退出,本地文件restartSize偏移量之后可能残留无效脏数据。新的下载流只会覆盖restartSize之后对应长度的内容,文件末尾残留的旧数据不会被清除,最终文件总大小和服务端一致,但字节序列存在错误,ZIP这类带完整性校验的压缩包会直接识别为损坏。- 现有代码缺少边界校验、事件顺序错误:首次下载本地无文件时
fs.statSync会直接抛错;pipe调用后才绑定data事件可能导致进度统计丢失;没有流错误、结束监听,容易出现资源泄漏。
修复后完整代码
const fs = require('fs'); clientFtp.on('ready', function(){ const serverFile = "example_file_on_server.zip"; const localFile = "example_file_on_client.zip"; let serverFileSize = 0; let restartSize = 0; clientFtp.list(serverFile, function(erreurListage, serverElementList) { if (erreurListage) throw erreurListage; if (!serverElementList?.length) throw new Error('Remote file not exist'); serverFileSize = serverElementList[0].size; // 计算续传偏移量,兼容本地文件不存在场景 try { const localFileInfo = fs.statSync(localFile); restartSize = localFileInfo.size; // 本地文件大小已超过/等于服务端文件,直接判定下载完成 if (restartSize >= serverFileSize) { console.log('Download already completed'); clientFtp.end(); return; } // 核心修复:截断本地文件到已确认下载完成的长度,清除残留脏数据 fs.truncateSync(localFile, restartSize); } catch (e) { // 本地文件不存在,从头开始下载 restartSize = 0; } clientFtp.restart(restartSize, function(erreurRedemarrage){ if (erreurRedemarrage) throw erreurRedemarrage; let tailleDownload = restartSize; // 区分首次下载/续传的文件打开模式 const writeStream = fs.createWriteStream(localFile, { flags: restartSize === 0 ? 'w' : 'r+', start: restartSize }); clientFtp.get(serverFile, function(erreurRecuperation, stream) { if (erreurRecuperation) throw erreurRecuperation; // 先绑定事件再pipe,避免漏收数据 stream.on('data', function(buffer){ tailleDownload += buffer.length; const pourcentageDownload = (tailleDownload / serverFileSize * 100).toFixed(0); console.log(pourcentageDownload); }); stream.on('end', () => { writeStream.end(); clientFtp.end(); }); stream.on('error', (err) => { writeStream.destroy(); clientFtp.destroy(); throw err; }); stream.pipe(writeStream); }); }); }); });
关键改动说明
- 续传前调用
fs.truncateSync将本地文件截断到已验证完成的restartSize长度,彻底清除历史残留的无效字节,从根源解决文件内容错乱问题 - 新增本地文件存在性判断,首次下载自动从头开始,不会因为找不到本地文件报错
- 增加本地与服务端文件大小校验,已完成下载时直接返回,不发起无效传输请求
- 调整事件绑定顺序,先绑定
data/error/end事件再执行pipe,避免进度统计丢失、异常未捕获问题 - 区分首次下载和续传的文件打开标识,首次下载用
w模式创建新文件,续传用r+模式从指定偏移写入,减少文件打开异常 - 增加流生命周期监听,下载完成、出错时正确关闭文件流和FTP连接,避免资源泄漏
内容的提问来源于stack exchange,提问作者Juan
相关产品推荐
相关产品推荐

