Node.js 计算文件哈希并保存文件

Node.js 计算文件哈希并保存文件,node.js,stream,Node.js,Stream,用户将文件上载到my express应用程序。我需要计算上传文件的散列,然后使用计算出的散列作为文件名将文件写入磁盘。我尝试使用以下代码执行此操作: function storeFileStream(file, next) { createFileHash(file, function(err, hash) { if (err) { return next(err); } var fileName = path.j

用户将文件上载到my express应用程序。我需要计算上传文件的散列,然后使用计算出的散列作为文件名将文件写入磁盘。我尝试使用以下代码执行此操作:

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);
}
此代码的问题是不会发出事件
end
finish
。如果我注释
file.pipe(s2)事件已发出,但我再次遇到起源问题。

您可以使用该模块(未测试,但应该可以工作):


此代码修复了以下问题:

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();
});

正确而简单的方法如下:

我们应该恢复经过的流程

函数storeFileStream(文件、目录、版本、拒绝、解析){
const fileHashSource=new PassThrough();
const writeSource=new PassThrough();
file.pipe(fileHashSource);
file.pipe(writeSource);
//这是关键点,请参见https://nodejs.org/api/stream.html#stream_three_states
fileHashSource.resume();
writeSource.resume();
createFileHash(fileHashSource,函数(err,hash){
如果(错误){
退货拒绝(err);
}
const fileName=path.join(目录,版本+'.'+hash.slice(0,8)+'.zip');
const writeStream=fs.createWriteStream(文件名);
writeStream.on('error',函数(err){
退货拒绝(err);
});
writeStream.on('finish',function(){
返回resolve();
});
writeSource.pipe(writeStream);
});
}
函数createFileHash(readStream,next){
const hash=crypto.createHash('sha1');
setEncoding('hex');
hash.on('error',函数(err){
返回下一个(错误);
});
hash.on('finish',函数(数据){
返回next(null,hash.read());
});
管道(散列);
}

由于您通过管道将文件流传输到哈希函数中,因此当您进行哈希运算并希望写入文件时,您已经完全耗尽了该流。您可以先将文件写入磁盘,然后再次读取以计算散列,或者需要提前复制流;请参阅,谢谢您的评论。第一个选项对我不好,因为我需要先计算散列。我尝试使用PassThrough stream复制流,并使用PassThrough的实例而不是
文件
参数。但是,现在不会发出“完成”和“结束”事件。我尝试了您的代码,但它有相同的问题:保存的文件为空。事实上,我不知道为什么它会对我有帮助。从已经传输的流中读取的问题仍然在这里表示,
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();
});