逐行读取gzip流

17
我有一个压缩的gzip文件,我想逐行读取它。
var fs = require('fs')
var zlib = require('zlib')
var gunzip = zlib.createGunzip()
var inp = fs.createReadStream('test.gz')
var n = 0

var lineProcessing = function (err, data) {
    if (!err) {
        n += 1
        console.log ("line: " + n)
        console.log (data.toString())
    }
}

inp
  .on('data', function (chunk) {
      zlib.gunzip (chunk, lineProcessing)
  })
  .on('end', function () {
    console.log ('ende');
  });

我猜我需要为zlib.createGunzip设置块大小,以便我只读取到下一个\n。但是如何动态确定它呢?

3个回答

28

使用readline可能更容易实现:

const fs       = require('fs');
const zlib     = require('zlib');
const readline = require('readline');

let lineReader = readline.createInterface({
  input: fs.createReadStream('test.gz').pipe(zlib.createGunzip())
});

let n = 0;
lineReader.on('line', (line) => {
  n += 1
  console.log("line: " + n);
  console.log(line);
});

@Tomas,你的意思是你想处理一个“常规”的流(而不是压缩的流)吗?你可以将任何可读流作为input参数使用。 - robertklep
我正在尝试使用从zlib.gunzip()返回的流。我的工作流程是:我从aws s3获取文件,使用gunzip解压缩它,然后将流传递给readline,但它抛出错误,可能是流不一致或其他原因吗? - Tomas
显然,一旦我使用gunzip解压文件,它传递的不是流而是字符串。 - Tomas
@Tomas zlib.gunzip() 不会返回流,它会在回调函数中返回解压后的数据。你可能需要同时使用 zlib.createGunzip() - robertklep
我尝试使用 data.pipe(zlib.createGunzip()) 进行操作,其中 data 是从 zlib.gunzip() 得到的被解压缩的缓冲区,但是我收到了一个错误,提示 data.pipe(zlib.createGunzip()) 不是一个函数。你对此有什么想法吗? - Tomas
显示剩余3条评论

10
如果有人几年后还在寻找如何使用async/await解决这个问题,以下是我正在使用的解决方案(TypeScript,但您可以省略类型注释)。
import fs from "fs";
import zlib from "zlib";
import readline from "readline";

const line$ = (path: string) => readline.createInterface({
    input: fs.createReadStream(path).pipe(zlib.createGunzip()),
    crlfDelay: Infinity
});

const yourFunction = async () => {
    for await (const line of line$("/path/to/file.txt.gz")) {
        // do stuff with line
    }
}

1
TypeError: line$(...) is not a function or its return value is not async iterable - d-_-b
你使用的是哪个运行时?我正在使用 Node v14.4.0 - Andrei

4

在TypeScript中逐行读取纯文本或gzip文件:

import * as fs from 'fs';
import * as zlib from 'zlib'
import * as readline from 'readline'

function readFile(path: string) {
    let stream: NodeJS.ReadableStream = fs.createReadStream(path)
    
    if(/\.gz$/i.test(path)) {
        stream = stream.pipe(zlib.createGunzip())
    }

    return readline.createInterface({
        input: stream,
        crlfDelay: Infinity
    })
}

async function main() {
    const lineReader = readFile('/usr/share/man/man1/less.1.gz')

    for await(const line of lineReader) {
        console.log(line)
    }
}

main().catch(err => {
    console.error(err);
    process.exit(1)
})


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接