Node.js流式Gzip写入文件异常:内容未被压缩为Gzip格式
问题排查:Gzip压缩写入文件后仍是明文
我尝试把Gzip压缩后的内容写入文件以减小体积,但读取时发现内容还是明文(比如hello there),而非预期的Gzip压缩格式(比如\u001f\ufffd\b\u0000\u0000\u0000...)。我编写了以下Node.js(v18.3.0)单元测试复现问题,但测试失败,寻求排查帮助:
import fs from 'fs' import path from 'path' import zlib from 'zlib' // ... it('wip general - check compression to file works', async () => { // create gzip pipe to file const filename = path.join(tmpdir.name, 'test.txt.gz') const test = zlib.createGzip().pipe(fs.createWriteStream(filename, 'utf-8')) // write some content, wait for it to finish writing test.write('hello there', 'utf-8') test.end() await new Promise(resolve => test.on('finish', resolve)) // check result is NOT plaintext expect(fs.readFileSync(filename, 'utf-8')).not.eql('hello there') })
测试失败输出:
AssertionError: expected 'hello there' to not deeply equal 'hello there'
问题原因与修复方案
核心问题
你把pipe()返回的文件写入流赋值给了test变量,后续调用test.write()和test.end()时,数据直接写入了文件流,完全绕过了Gzip压缩流,自然不会产生压缩内容。
修正后的代码
import fs from 'fs' import path from 'path' import zlib from 'zlib' it('wip general - check compression to file works', async () => { const filename = path.join(tmpdir.name, 'test.txt.gz') // 分别创建Gzip流和文件流,明确操作Gzip流 const gzipStream = zlib.createGzip() const fileStream = fs.createWriteStream(filename) gzipStream.pipe(fileStream) // 往Gzip流写入数据,数据会被压缩后再流向文件 gzipStream.write('hello there', 'utf-8') gzipStream.end() // 监听文件流的finish事件,确保压缩后的内容完全写入文件 await new Promise(resolve => fileStream.on('finish', resolve)) // 读取文件Buffer,验证结果 const fileContent = fs.readFileSync(filename) // 验证内容不是明文 expect(fileContent.toString('utf-8')).not.eql('hello there') // 额外验证:Gzip格式的魔数是0x1f8b,检查文件开头是否符合 expect(fileContent.slice(0, 2).toString('hex')).toBe('1f8b') })
额外注意点
- 创建文件流时不要指定
'utf-8'编码:Gzip压缩内容是二进制数据,用默认的Buffer模式写入即可,避免编码转换破坏压缩结果。 - 读取文件优先用Buffer:直接读取为Buffer能更准确判断压缩状态,转换为字符串时可能因编码问题出现乱码,属于正常现象。
内容的提问来源于stack exchange,提问作者Nick Grealy
相关产品推荐
相关产品推荐

