计算文件哈希并保存文件

时间:2015-06-15 08:43:23

标签: node.js stream

用户将文件上传到我的快递应用中。我需要计算上传文件的哈希值,然后使用计算的哈希作为文件名将文件写入磁盘。我尝试使用以下代码执行此操作:

function storeFileStream(file, next) {
    createFileHash(file, function(err, hash) {
        if (err) {
            return next(err);
        }

        var fileName = path.join(config.storagePath, hash),
            stream = fs.createWriteStream(fileName);

        stream.on('error', function(err) {
            return next(err);
        });
        stream.on('finish', function() {
            return next();
        });

        file.pipe(stream);
    });
}

function createFileHash(file, next) {
    var hash = crypto.createHash('sha1');
    hash.setEncoding('hex');

    file.on('error', function(err) {
        return next(err);
    });
    file.on('end', function(data) {
        hash.end();
        return next(null, hash.read());
    });

    file.pipe(hash);
}

问题是在我计算文件哈希后,写入的文件大小是0.解决此任务的最佳方法是什么?

更新 根据@poke建议我尝试复制我的流。现在我的代码是:

function storeFileStream(file, next) {
    var s1 = new pass;
    var s2 = new pass;
    file.pipe(s1);
    file.pipe(s2);        

    createFileHash(s1, function(err, hash) {
        if (err) {
            return next(err);
        }

        var fileName = path.join(config.storagePath, hash),
            stream = fs.createWriteStream(fileName);

        stream.on('error', function(err) {
            return next(err);
        });
        stream.on('finish', function() {
            return next();
        });

        s2.pipe(stream);
    });
}

function createFileHash(file, next) {
    var hash = crypto.createHash('sha1');
    hash.setEncoding('hex');

    file.on('error', function(err) {
        return next(err);
    });
    file.on('end', function(data) {
        hash.end();
        return next(null, hash.read());
    });

    file.pipe(hash);
}

此代码的问题是不会发出事件endfinish。如果我评论file.pipe(s2);事件已经发出,但我再次得到我的原始问题。

3 个答案:

答案 0 :(得分:0)

您可以使用async模块(未经测试但应该可以使用):

async.waterfall([
    function(done) {
        var hash = crypto.createHash('sha1');
        hash.setEncoding('hex');

        file.on('error', function(err) {
            done(err);
        });
        file.on('end', function(data) {
            done(null, hash.read);
        });

        file.pipe(hash);

    },
    function(hash, done) {
        var fileName = path.join(config.storagePath, hash),
            stream = fs.createWriteStream(fileName);

        stream.on('error', function(err) {
            done(err);
        });
        stream.on('finish', function() {
            done(null);
        });

        file.pipe(stream);
    }
], function (err) {
    console.log("Everything is done!");
});

答案 1 :(得分:0)

此代码解决了问题:

var s1 = new passThrough,
    s2 = new passThrough;

file.on('data', function(data) {
    s1.write(data);
    s2.write(data);
});
file.on('end', function() {
    s1.end();
    s2.end();
});

答案 2 :(得分:0)

正确且简单的方法应该如下:

我们应该恢复传递的流

function storeFileStream(file, directory, version, reject, resolve) {
  const fileHashSource = new PassThrough();
  const writeSource = new PassThrough();
  file.pipe(fileHashSource);
  file.pipe(writeSource);

  // this is the key point, see https://nodejs.org/api/stream.html#stream_three_states
  fileHashSource.resume();
  writeSource.resume();

  createFileHash(fileHashSource, function(err, hash) {
    if (err) {
      return reject(err);
    }

    const fileName = path.join(directory, version + '_' + hash.slice(0, 8) + '.zip');
    const writeStream = fs.createWriteStream(fileName);

    writeStream.on('error', function(err) {
      return reject(err);
    });
    writeStream.on('finish', function() {
      return resolve();
    });

    writeSource.pipe(writeStream);
  });
}

function createFileHash(readStream, next) {
  const hash = crypto.createHash('sha1');
  hash.setEncoding('hex');

  hash.on('error', function(err) {
    return next(err);
  });
  hash.on('finish', function(data) {
    return next(null, hash.read());
  });

  readStream.pipe(hash);
}