当下载文件很大时,节点FTP不会执行“一次”(“closures”)callback

我有一个从FTP服务器下载文件的方法,它可以在较小的文件上正常工作,但是当我使用它下载~5GB大小的zip文件时,它会下载它,但是之后它什么也不做。 当达到下载的100%时,脚本不会继续。 下载完成后我是否应该等待在后台真正做了些什么? 是否有文件大小限制?

const FTP = require('ftp') 

可以在npm上find

 downloadFile: params => { return new Promise((resolve, reject) => { let ftpClient = new FTP() let total = params.state.fileSize let progress = 0 ftpClient.on('ready', _ => { console.log(`Downloading ${params.targetedFile} ...`); ftpClient.get(params.targetedFile, (err, stream) => { if (err) reject(err) stream.on('data', buffer => { progress += buffer.length process.stdout.write(`Progress: ${(progress/total*100).toFixed(2)}% (${progress}/${total}) \r`) }) stream.once('close', _ => { ftpClient.end() console.log(`Saved downloaded file to ${params.localDir}`); resolve(params.localDir) }) stream.pipe(fs.createWriteStream(params.localDir)) }) }) ftpClient.connect(params.auth) }) } 

基本上,当下载大文件时, stream.once('close', ...)的callback不会被执行。 它会被执行到相同types的较小文件。

我build议您处理closures写入stream的事件。

原因很简单:我们从ftp的读取stream和pipe道读取stream,一切正常,文件成功closures。

所以代码:

 downloadFile: params => { return new Promise((resolve, reject) => { let ftpClient = new FTP() let total = params.state.fileSize let progress = 0 ftpClient.on('ready', _ => { console.log(`Downloading ${params.targetedFile} ...`); ftpClient.get(params.targetedFile, (err, stream) => { if (err) { ftpClient.end(); return reject(err); } stream.on('data', buffer => { progress += buffer.length process.stdout.write(`Progress: ${(progress/total*100).toFixed(2)}% (${progress}/${total}) \r`) }); // opening writeStream to file let finished = false; const writeStream = fs.createWriteStream(params.localDir); writeStream.on('finish', (result) => { // handling finish finished = true; ftpClient.end(); console.log(`Finish triggered ${params.localDir}`); console.log(result); resolve(params.localDir); }); writeStream.on('close', (result) => { // handling close ftpClient.end(); console.log(`Close triggered ${params.localDir}`); console.log(result); resolve(params.localDir); }) // piping readStream to writeStream stream.pipe(writeStream); }) }) ftpClient.connect(params.auth) }) } 

这段代码可能让你知道如何处理这个有点怪异的方式。

基本上这个方法允许你从FTP服务器下载文件并保存到本地文件系统。 它在一行中输出当前进度complete_percentage% (current/total) 。 一旦完成,它解决了承诺,返回到本地文件的path,您作为parameter passing相同的一个。

 /** * @name downloadFile * @desc downloads file from FTP server * @param params, Object of params * @prop auth: object, or null, authorization params * @prop targetedFile: {String} filename eg data.txt * @prop localDir: {String} filename on local disk * @prop state: {Object} fileinfo object, {Int} .fileSize property is required * @return Promise, resolves given localDir */ downloadFile: params => { return new Promise((resolve, reject) => { // validate param types if(typeof params.auth !== 'object' || typeof params.targetedFile !== 'string' || typeof params.localDir !== 'string' || typeof params.state !== 'object' || typeof params.state.fileSize !== 'number' ) throw new Error('You are either missing properties or passed wrong types') // initialize let ftpClient = new FTP() let total = params.state.fileSize let progress = 0 // ftpClient.on('ready', _ => { console.log(`Downloading ${params.targetedFile} ...`) // get file ftpClient.get(params.targetedFile, (err, stream) => { if (err){ ftpClient.end() return reject(err) } // upon data receive stream.on('data', buffer => { progress += buffer.length // if progress is complete if(progress === total){ // start checking if local filesize matches server filesize let interval = setInterval(_ => { if(fs.statSync(params.localDir).size === total){ console.log(`Downloading file complete. Location: ${params.localDir}`); clearInterval(interval) ftpClient.end() resolve(params.localDir) } }) } // show current progress in percentages and bytes process.stdout.write(`Progress: ${(progress/total*100).toFixed(2)}% (${progress}/${total}) \r`) }) // pipe writestream to filesystem to write these bytes stream.pipe(fs.createWriteStream(params.localDir)) }) }) ftpClient.connect(params.auth) })//promise }