当下载文件很大时,节点FTP不会执行`一次('关闭')`回调

Kun*_*nok 6 javascript ftp-client node.js

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

const FTP = require('ftp')
Run Code Online (Sandbox Code Playgroud)

可以在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)
    })
  }
Run Code Online (Sandbox Code Playgroud)

基本上,stream.once('close', ...)下载大文件时不会执行回调.并且它会针对相同类型的较小文件执行.

Kun*_*nok 0

这段代码可能会让您了解如何以一种有点古怪的方式处理这个问题。

基本上,此方法允许您从 FTP 服务器下载文件并将其保存到本地文件系统。complete_percentage% (current/total)它在一行中输出当前进度。完成后,它解析 Promise,返回本地文件的路径,与您作为参数传递的路径相同。

/**
   * @name downloadFile
   * @desc downloads file from FTP server
   * @param  params, Object of params
   *   @prop auth: object, or null, authorization params
   *   @prop targetedFile: {String} filename e.g. 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
  }
Run Code Online (Sandbox Code Playgroud)