Tengo un método para descargar archivos desde un servidor FTP y funciona bien en archivos más pequeños, pero cuando lo uso para descargar un archivo de ~5 GB de tamaño de tipo zip, lo descarga, pero luego no hace nada. Cuando alcanza el 100% de la descarga, el script no continúa. ¿Debo esperar si realmente está haciendo algo en segundo plano después de que se complete la descarga? ¿Hay límite de tamaño de archivo?
const FTP = require('ftp')que se puede encontrar en npm
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) }) } Básicamente, la devolución de llamada para stream.once('close', ...) no se ejecuta cuando se descarga un archivo grande. Y se ejecuta para un archivo más pequeño del mismo tipo.
Le recomiendo que maneje el evento de cerrar el flujo de escritura.
La razón es simple: leemos desde el flujo de lectura de ftp y canalizamos para escribir el flujo, todo está bien, cuando el archivo se cierra con éxito.
Así que código:
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) }) }Este código podría darle una idea de cómo manejar esto de una manera un poco rara.
Básicamente, este método le permite descargar archivos del servidor FTP y guardarlos en el sistema de archivos local. Muestra el progreso actual complete_percentage% (current/total) en una sola línea. Al finalizar, resuelve la promesa, devuelve la ruta al archivo local, la misma que pasó como parámetro.
/** * @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 }