JavaScript で JSONL を扱う:読み取り・書き込み・解析

JavaScript で JSONL(JSON Lines)ファイルを扱うための完全ガイド。組み込み API と人気ライブラリを使用して、Node.js とブラウザの両方で JSONL データの読み取り、書き込み、解析、ストリーミングを学びます。

最終更新:2026年2月

なぜ JavaScript で JSONL を扱うのか?

JavaScript は JSONL ファイルを扱うのに最適な言語です。JSON はもともと JavaScript から生まれたものであり、組み込みの JSON.parse() と JSON.stringify() メソッドによるファーストクラスの解析サポートを備えています。Node.js のデータパイプラインの構築、サーバー上でのログファイル処理、ブラウザでのユーザーによる JSONL アップロードなど、JavaScript はあらゆるステップに対応するツールを提供します。

JSONL(JSON Lines)は 1 行に 1 つの JSON オブジェクトを格納するため、ストリーミング、追記専用ログ、大規模データセットの行単位処理に最適です。Node.js のストリームはこの形式と完全に適合し、メモリ不足になることなく数百万件のレコードを読み取り・変換できます。クライアント側では、ブラウザの FileReader API と Streams API により、ユーザーのデバイス上で完全に JSONL 処理が可能です。このガイドでは、Node.js とブラウザの両方で JSONL を読み取る方法、JSONL ファイルの書き込み、ストリーミング変換パイプラインの構築、プロジェクトに適した npm ライブラリの選択方法を学びます。

Node.js で JSONL を読み取る

Node.js は readline モジュールを使用してファイルを効率的に行単位で読み取ることができます。fs.createReadStream と組み合わせることで、ファイル全体をメモリに読み込む代わりにデータをストリーミングするため、サーバー上で JSONL ファイルを処理する推奨方法です。

fs.createReadStream を readline.createInterface にパイプして、JSONL ファイルを 1 行ずつ読み取ります。このアプローチはファイルサイズに関係なく最小限のメモリで動作します。

readline によるストリーム読み取り
import { createReadStream } from 'node:fs';
import { createInterface } from 'node:readline';
async function readJsonl(filePath) {
const records = [];
const rl = createInterface({
input: createReadStream(filePath, 'utf-8'),
crlfDelay: Infinity,
});
for await (const line of rl) {
const trimmed = line.trim();
if (trimmed) {
records.push(JSON.parse(trimmed));
}
}
return records;
}
// Usage
const data = await readJsonl('data.jsonl');
console.log(`Loaded ${data.length} records`);
console.log(data[0]);

メモリに余裕がある小さな JSONL ファイルの場合、ファイル全体を一度に読み込んで改行で分割できます。ストリーミング効率の代わりにシンプルさを重視したアプローチです。

ワンライナー(小さなファイル向け)
import { readFileSync } from 'node:fs';
const records = readFileSync('data.jsonl', 'utf-8')
.split('\n')
.filter(line => line.trim())
.map(line => JSON.parse(line));
console.log(`Loaded ${records.length} records`);

ブラウザで JSONL を読み取る

ブラウザでは、ユーザーがファイル入力を通じて JSONL ファイルをアップロードできます。FileReader API または最新の Streams API を使用してファイルを読み取ることができ、サーバーにデータを送信する必要はありません。

FileReader を使用してユーザーが選択したファイルを読み取り、テキストコンテンツを行に分割して各行を解析します。すべてのデータをクライアント側で保持するためプライバシーが守られます。

ブラウザ FileReader API
function parseJsonlFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
const text = reader.result;
const records = text
.split('\n')
.filter(line => line.trim())
.map(line => JSON.parse(line));
resolve(records);
};
reader.onerror = () => reject(reader.error);
reader.readAsText(file, 'utf-8');
});
}
// Usage with an <input type="file"> element
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async (e) => {
const file = e.target.files[0];
const records = await parseJsonlFile(file);
console.log(`Parsed ${records.length} records`);
});

ブラウザで大容量ファイルを処理する場合、Streams API と TextDecoderStream を使用してファイルをチャンク単位で処理します。ファイル全体を一度にメモリに読み込むことを回避できます。

ブラウザ Streams API(大容量ファイル向け)
async function* streamJsonl(file) {
const stream = file.stream()
.pipeThrough(new TextDecoderStream());
const reader = stream.getReader();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += value;
const lines = buffer.split('\n');
buffer = lines.pop(); // Keep incomplete last line
for (const line of lines) {
const trimmed = line.trim();
if (trimmed) yield JSON.parse(trimmed);
}
}
// Handle remaining buffer
if (buffer.trim()) {
yield JSON.parse(buffer.trim());
}
}
// Usage
for await (const record of streamJsonl(file)) {
console.log(record);
}

Node.js で JSONL を書き込む

Node.js で JSONL ファイルを書き込むのは簡単です。各 JavaScript オブジェクトを JSON 文字列にシリアライズし、改行文字を追加します。大規模データセットでは、メモリ内で文字列全体を構築する代わりに、書き込みストリームを使用することでパフォーマンスが向上します。

fs.writeFileSync または fs.createWriteStream を使用してレコードを JSONL ファイルに書き込みます。各レコードは有効な JSON の 1 行に続く改行文字です。

fs を使った基本的な書き込み
import { writeFileSync } from 'node:fs';
const records = [
{ id: 1, name: 'Alice', role: 'engineer' },
{ id: 2, name: 'Bob', role: 'designer' },
{ id: 3, name: 'Charlie', role: 'manager' },
];
const jsonl = records
.map(record => JSON.stringify(record))
.join('\n') + '\n';
writeFileSync('output.jsonl', jsonl, 'utf-8');
console.log(`Wrote ${records.length} records`);

数百万件のレコードを書き込む場合、出力文字列全体をメモリ内で構築しないように書き込みストリームを使用します。ストリームはバックプレッシャーを自動的に処理し、OS バッファがいっぱいになると書き込みを一時停止します。

大規模データのストリーミング書き込み
import { createWriteStream } from 'node:fs';
async function writeJsonl(filePath, records) {
const stream = createWriteStream(filePath, 'utf-8');
for (const record of records) {
const line = JSON.stringify(record) + '\n';
// Respect backpressure
if (!stream.write(line)) {
await new Promise(resolve => stream.once('drain', resolve));
}
}
stream.end();
await new Promise(resolve => stream.on('finish', resolve));
console.log('Write complete');
}
// Usage
const data = Array.from({ length: 100000 }, (_, i) => ({
id: i + 1,
value: Math.random(),
timestamp: new Date().toISOString(),
}));
await writeJsonl('large_output.jsonl', data);

JSONL パイプライン向けの Transform ストリーム

Node.js の Transform ストリームを使用すると、JSONL を読み取り、各レコードを処理し、結果を書き込む構成可能なデータパイプラインを構築できます。このパターンは ETL ジョブ、ログ処理、データ移行に最適です。

JSONL パイプライン向けの Transform ストリーム
import { createReadStream, createWriteStream } from 'node:fs';
import { createInterface } from 'node:readline';
import { Transform } from 'node:stream';
import { pipeline } from 'node:stream/promises';
// Transform: parse JSONL line into object, process, stringify back
const transformJsonl = new Transform({
objectMode: true,
transform(chunk, encoding, callback) {
const line = chunk.toString().trim();
if (!line) return callback();
try {
const record = JSON.parse(line);
// Add your transformation here
record.processed = true;
record.processedAt = new Date().toISOString();
callback(null, JSON.stringify(record) + '\n');
} catch (err) {
callback(err);
}
},
});
// Build the pipeline
const rl = createInterface({
input: createReadStream('input.jsonl', 'utf-8'),
crlfDelay: Infinity,
});
const output = createWriteStream('output.jsonl', 'utf-8');
for await (const line of rl) {
transformJsonl.write(line);
}
transformJsonl.end();
await pipeline(transformJsonl, output);
console.log('Pipeline complete');

このパイプラインは JSONL ファイルを行単位で読み取り、各レコードに変換を適用し(processed と processedAt フィールドを追加)、結果を新しいファイルに書き込みます。Transform ストリームはバックプレッシャーを自動的に処理するため、非常に大きなファイルでもメモリ使用量は一定に保たれます。複雑な ETL ワークフローでは複数の変換をチェーンできます。

JSONL 向け JavaScript ライブラリ

組み込みの JSON.parse がほとんどのケースをうまく処理しますが、ストリーミング、バリデーション、バッチ処理など JSONL 固有のワークフローに便利なユーティリティを提供する npm パッケージがいくつかあります。

JSON.parse(組み込み)

組み込み

組み込みの JSON.parse() と JSON.stringify() は V8 で高度に最適化されており、ほとんどの JSONL ユースケースに十分です。readline と組み合わせてストリーミングに使用します。依存関係不要で、数百 MB までのファイルに対して優れたパフォーマンスを発揮します。

ndjson

人気

ndjson は、Node.js ストリームと互換性のあるストリーミング JSONL(改行区切り JSON)パーサーとシリアライザーを提供する人気の npm パッケージです。解析エラーを適切に処理し、既存のストリームパイプラインとうまく統合できます。迅速なプロトタイピングに最適です。

jsonl-parse-stringify

シンプル

jsonl-parse-stringify は、JSONL データ用のシンプルな parse() と stringify() メソッドを提供する軽量でゼロ依存のライブラリです。末尾の改行や空行などのエッジケースを処理します。ストリームのセットアップなしでクリーンな同期 API が必要な場合に最適です。

無料の JSONL ツールを試す

コードを書きたくないですか?無料のオンラインツールを使って、ブラウザで直接 JSONL ファイルの表示、変換、フォーマットができます。すべての処理はローカルで行われるため、データのプライバシーが守られます。

JSONL ファイルをオンラインで操作

最大 1GB の JSONL ファイルをブラウザで直接表示、検証、変換。アップロード不要、100% プライベート。

よくある質問

JavaScript で JSONL — Node で JSON Lines を読み取り・書き込み&ストリーミング...