Nodejs で stream を使って gzip ファイル全体をメモリに乗せずに先頭一行だけを取得する
2019-12-23 Mon.
この記事は Node.js アドベントカレンダー 2019 の 23 日目です。
はじめに
gzip ファイルなどの圧縮されたファイルを読み込む際、たとえば csv など圧縮率の高いファイル形式かつ大きなファイルの場合、全てをメモリに乗せ切れないことが稀にあります。 そもそも csv のカラムだけ欲しいなどの場合にデータ全体を取得するのは時間もかかるし無駄です。 そこで、 Node.js は stream を扱いやすい言語なので、これを使って簡単に解決できるため紹介します。
なお、 S3 からのデータ取得であっても createReadStream()
すれば stream.Readable
型になるため、同様の手法が可能です。そもそも、この話自体がローカルよりはクラウド絡みの方が多いケースになると思いますが……。
おさらい: Node.js での stream でのファイル読み書き
例えば、ファイルを読み込んで標準出力に表示します。
書き込みの例として、大きなサイズの csv を生成するスクリプトをファイルに書き込みます。
大きなデータなので複数に別れて buffer で流れます。データが来るたびに区切り文字を表示して標準出力に表示する場合はこうです。
gzip の展開を stream に適用する
標準ライブラリの zlib から pipe を作成し適用します。
先頭一行を取得する
普通に buf.toString()
した値を "\n"
で split できます。
なお、 stream.destroy()
が間に合わず次のデータが流れてくることは普通にあるので、一度限りの処理に限定できるよう関数に切り出すのが良さそうです。
おまけ: S3 から取得した gzip の先頭一行を取得する
s3.getObject().createReadStream()
するだけです。 await は要りません。
おわりに
大きなデータを扱うときは、メモリに乗り切らないこともあるので stream を使いましょう。
Other Works
2024-05-11 Sat.
Powerfully Typed TypeScript
- TSKaigi 2024
2024-05-10 Fri.
pnpm の node_modules を探検して理解しよう
- ドワンゴ教育サービス開発者ブログ
2024-03-17 Sun.
neverthrow で局所的に Result 型を使い、 try-catch より安全に記述する
- Zenn
2023-12-20 Wed.
レガシーブラウザ向けのビルドオプションを剪定する
- ドワンゴ教育サービス開発者ブログ
2023-05-26 Fri.
Next.js で dynamic import を使い Client だけで動かす Component を実現する
- Zenn
2023-05-02 Tue.
Node.js でファイル名から拡張子を取り除く/取り出すために path.parse を使う
- Zenn
2023-02-27 Mon.
WSL2 で外部からアクセス可能にするために bridge mode を有効にする
- Zenn
2023-01-26 Thu.
init.vim & dein から init.lua & lazy.nvim へ、シンプル設定で移行した
- Zenn
2023-01-13 Fri.
kindle の本をブクログ形式の csv でエクスポートする@2023初春
- Zenn
2023-01-10 Tue.
自宅サーバの移設に際して docker から nerdctl に移行した
- Zenn
2023-01-10 Tue.
自宅サーバを rootless に移行した際のトラブル対応
- Zenn
2021-11-11 Thu.
並列実行した Promise で throw されても全てハンドルしたいときの方法(allSettled, finally, etc...)
- Zenn