NodeJS - 管道到writeStream并等待完成事件

时间:2018-01-20 13:13:45

标签: javascript file stream

我在尝试通过HTTP下载文件时使用以下代码。我试图使用流,因为文件非常大。我遇到的问题是,在将响应传递给创建的WritableStream之后,有时文件没有被创建,因此在检查校验和时代码会出错。

换句话说,'完成'即使文件不存在/尚未创建,WritableStream的事件也会触发。

exports.downloadHttpFile = function(url, path, mimeType, checksum) {
    return exports.get(url, mimeType, false).then(function(res) {
        if (res.statusCode != 200) {
            return Promise.reject(new Error('Invalid response from server when trying to download file'))
        } else {
            return new Promise(function(resolve, reject) {
                console.log('creating file at ' + path)
                const writable = fs.createWriteStream(path);

                writable.once('open', () => res.pipe(writable).once('error', reject)).on('finish', function() {
                    writable.end();
                    try {
                        if (checksum) {
                            console.log(checksum)
                            if (!checksum.hashType || !checksum.hashEncoding || !checksum.hashValue) return reject(new Error('Invalid checksum object'))

                            fs.createReadStream(path)
                                .once('error', function() {
                                    console.log('ERRORS OUT HERE, FILE NO EXIST (path not created by fs.createWriteStream)')
                                })
                                .pipe(require('crypto').createHash(checksum.hashType).setEncoding(checksum.hashEncoding))
                                .once('finish', function() {
                                    const fileHash = this.read();
                                    if (fileHash != checksum.hashValue) {
                                        try {
                                            fs.unlinkSync(path);
                                        } catch (err) {}
                                        return reject(new Error('Downladed file checksum did not match given checksum'));
                                    } else {
                                        return resolve(path);
                                    }
                                }).once('error', reject)
                        } else {
                            return resolve(path);
                        }
                    } catch (err) {
                        console.log('File did not exist after piping to writable stream..')
                        return reject(err);
                    }
                }).once('error', reject);
            });
        }
    })
}

有人可以这么好,告诉我哪里出错了吗?感谢

1 个答案:

答案 0 :(得分:0)

我设法通过检查文件是否存在以及是否不调用downloadHttpFile来解决此问题。我知道这不是一个非常好的解决方案,我不确定为什么它会在文件尚未创建的情况下触发完成事件..但是除非有人有更好的解决方案,否则它现在会做。

代码如下:

exports.downloadHttpFile = function (url, path, mimeType, checksum) {
  return exports.get(url, mimeType, false).then(function (res) {
    if (res.statusCode != 200) {
      return Promise.reject(new Error('Invalid response from server when trying to download file'))
    } else {
      return new Promise(function (resolve, reject) {
        const writable = fs.createWriteStream(path)

        writable.on('finish', function () {
          let pathExists = false
          try {
            fs.statSync(path)
            pathExists = true
          } catch (err) {}

          if (pathExists) {
            if (checksum) {
              console.log(checksum)
              if (!checksum.hashType || !checksum.hashEncoding || !checksum.hashValue) return reject(new Error('Invalid checksum object'))

              console.log('creating read stream for path ' + path)
              fs.createReadStream(path)
                .pipe(require('crypto').createHash(checksum.hashType).setEncoding(checksum.hashEncoding).once('error', function (err) {
                  console.log('Error creating crc code')
                  return reject(err)
                }))
                .once('finish', function () {
                  console.log('Finished reading stream')
                  const fileHash = this.read()
                  if (fileHash != checksum.hashValue) {
                    console.log('Checksums did not match')
                    console.log(fileHash)
                    console.log(checksum.hashValue)
                    return reject(new Error('Downladed file checksum did not match given checksum'))
                  } else {
                    console.log('Checksums matched')
                    return resolve(path)
                  }
                }).once('error', reject)
            } else {
              return resolve(path)
            }
          } else {
            console.log('File did not exist.. attempting to redownload' + path)
            return resolve(exports.downloadHttpFile(url, path, mimeType, checksum))
          }
        }).on('error', function (err) {
          console.log(err)
          return reject(err)
        })

        res.pipe(writable).on('error', function (err) {
          console.log('Error reading response')
          return reject(err)
        })
      })
    }
  })
}