Node.js 我怎样才能避免zlib“;意外的文件结尾“;在压缩部分文件时?
我试图在解压缩gzip文件时读取它的一部分,这样我就可以在不读取不必要字节的情况下解析头内容。我以前使用Node.js 我怎样才能避免zlib“;意外的文件结尾“;在压缩部分文件时?,node.js,zlib,Node.js,Zlib,我试图在解压缩gzip文件时读取它的一部分,这样我就可以在不读取不必要字节的情况下解析头内容。我以前使用fs.read()将选项传递到只读取前500个字节,然后使用zlib.gunzip()在从二进制数据解析头之前解压缩内容 在node v5.0.0修补了一个bug以确保zlib在被截断的输入上抛出一个错误之前,这一切都很正常() 现在我从zlib得到以下错误 Error: unexpected end of file 知道我正在截断输入而不抛出错误,我如何解压这个部分文件。我认为使用流可能更
fs.read()
将选项传递到只读取前500个字节,然后使用zlib.gunzip()
在从二进制数据解析头之前解压缩内容
在node v5.0.0修补了一个bug以确保zlib在被截断的输入上抛出一个错误之前,这一切都很正常()
现在我从zlib得到以下错误
Error: unexpected end of file
知道我正在截断输入而不抛出错误,我如何解压这个部分文件。我认为使用流可能更容易,所以我写了以下内容
var readStream = fs.createReadStream(file.path, {start: 0, end: 500});
var gunzip = zlib.createGunzip();
readStream.pipe(gunzip)
.on('data', function(chunk) {
console.log(parseBinaryHeader(chunk));
console.log('got %d bytes of data', chunk.length);
})
.on('error', function (err) {
console.log(err);
})
.on('end', function() {
console.log('end');
});
我的parseBinaryHeader()
函数正在返回正确的标题内容,因此我知道它正在解压缩,但当它到达输入的末尾时仍然抛出错误。我可以添加错误监听器来处理错误,但这似乎并不理想
有什么想法吗?谢谢你的建议。我还向节点存储库提交了一个问题,并获得了一些良好的反馈。这就是最终对我有用的东西
- 将区块大小设置为完整标题大小
- 将单个块写入解压缩流,并立即暂停流
- 处理解压缩的块
var bytesRead = 500;
var decompressStream = zlib.createGunzip()
.on('data', function (chunk) {
parseHeader(chunk);
decompressStream.pause();
}).on('error', function(err) {
handleGunzipError(err, file, chunk);
});
fs.createReadStream(file.path, {start: 0, end: bytesRead, chunkSize: bytesRead + 1})
.on('data', function (chunk) {
decompressStream.write(chunk);
});
到目前为止,它一直在工作,还允许我继续处理所有其他gunzip错误,因为pause()可以防止解压缩流抛出“意外的文件结尾”错误。我在尝试结束对NodeJS Gzip流的处理时遇到了同样的问题。我使用“buffer peek stream”检查gzip流的头,确定它实际上是一个gzip流。然后,我打开流的前几兆字节,查看该文件的内部并确定gzip内容的mime类型 这需要对zlib.createGunzip()进行两次调用 我发现,即使我创建了看起来像是gunzip转换的两个独立实例,破坏第二个实例也会导致第一个实例抛出这个“意外的文件结尾”错误。即使第一个实例处于完全不同的环境中
在我的例子中,修复方法是在创建第二个实例之前,在第一个实例上调用.destroy()来清理它。我在使用节点v10.13.0时遇到了这个错误。我升级到了v10.19.0,它已经修复。是否不输入截断的文件?它应该警告您输入基本上已损坏。因此,我如何解决更大的问题,即需要高效地读取一堆文件的标题,而不关心其余内容。文件数量和大小各不相同,但我通常阅读30多个文件,总容量为2-5GB。我只需要每个文件的前500字节。我试着完整地读取每个文件,但性能差异非常显著。try/catch错误?除非zlib有一个可以启用的“忽略错误”标志,否则您将无法处理它将抛出的内容,或者只编写自己的解压库。您可以直接使用
zlib.createGunzip
或zlib.createGunzipSync
而不使用流吗?您应该能够向它提供部分压缩数据和可用的未压缩数据。一旦你得到了你想要的东西,杀死这些东西。谢谢@MarkAdler。我做了类似的事情。我向Gunzip流中写入了一个块,然后立即暂停该流以避免意外的文件结尾。这允许我继续处理所有其他gunzip错误。parseHeader(块)来自哪里?在我的例子中,它说parseHeader没有定义。不幸的是,这个答案不完整parseHeader
未定义,HandleGunziperor也未定义。那么,您能否解释一下如何在不引发“意外的文件结尾”错误的情况下解析gzip块?@h0r53对于这个问题的上下文,parseHeader
和handlegunziperor
的细节其实并不重要。您可以将它们替换为console.log
,并根据自己的喜好处理每个文件的内容<代码>块只是文件的解压缩部分。如何解析它将取决于它是什么类型的文件以及您的具体需求。您甚至不需要进一步分析。@Constellates我认为chunk
的目的是发送数据片段,在gzip
+chunk
的情况下,数据首先通过gzip
压缩,然后跨一个或多个数据包进行分块。不是这样吗?@h0r53很接近。在这个例子中,我打开一个流来读取一个文件。该文件已被压缩。每次文件流从该gzip文件中读取新的数据块时,它都会调用decompressStream.write
。zlib gunzip对象(decompressStream
)依次解压缩每个块,并将解压缩后的文件块传递给parseHeader
。因此,如果您将其替换为console.log,您应该会看到解压缩文件的片段。