NodeJS中文件流直接哈希与写入本地再哈希结果不一致问题
问题根因
- Node.js 中的可读流为单次消费资源:你先将HTTP响应流通过
stream.pipe(file)全部写入磁盘后,流的读取指针已经移动到末尾,此时再把同一个流传入hashFileStream计算哈希时,已经没有任何数据可读取,得到的是空内容的哈希值,因此和本地文件的哈希结果不一致。 - 对于同一组二进制数据,直接通过流计算哈希、写盘后再读取计算哈希的结果必然一致,你当前的问题和编码无关。
修复方案
有两种常用修复思路:
方案1:使用PassThrough分流,一次请求同时完成写盘和哈希计算
这种方案不需要重复读取数据,性能最优:
const fs = require("fs"); const crypto = require("crypto"); const https = require("https"); const { PassThrough } = require("stream"); (async ()=>{ const testUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/SIPI_Jelly_Beans_4.1.07.tiff/lossy-page1-256px-SIPI_Jelly_Beans_4.1.07.tiff.jpg" const filePath = "./testFile.jpg"; https.get(testUrl, async function(response) { // 拆分两个流分别用于写盘和算哈希 const streamForWrite = new PassThrough(); const streamForHash = new PassThrough(); response.pipe(streamForWrite); response.pipe(streamForHash); // 并行执行写盘和哈希计算 const [_, streamHash] = await Promise.all([ writeFile(filePath, streamForWrite), hashFileStream(streamForHash) ]); const fileHash = await hashLocalFile(filePath) console.log("Stream Hash", streamHash); console.log("File hash", fileHash); }); })() async function writeFile(filePath, stream) { return new Promise((resolve, reject) => { const file = fs.createWriteStream(filePath); stream.pipe(file) .on('finish', () => { resolve(filePath); }) .on('error', (error)=>{ console.error(error); reject(error); }) }) } async function hashFileStream(stream){ return new Promise((resolve, reject)=>{ const hash = crypto.createHash('md5').setEncoding('hex'); stream.pipe(hash) .on('finish', ()=>{ resolve(hash.read()) }) .on('error', (error)=>{ reject(error) }) }) } async function hashLocalFile(filepath){ const readStream = fs.createReadStream(filepath); return hashFileStream(readStream); }
方案2:调整执行顺序,避免重复消费流
如果不需要同时拿到流哈希和本地文件哈希,可以调整逻辑:
- 先计算响应流哈希,再分流写入磁盘
- 或者写盘完成后,直接读取本地文件计算哈希即可,无需再用原始响应流计算
内容的提问来源于stack exchange,提问作者Deftwun
相关产品推荐
相关产品推荐

