JavaScript 處理 JSONL:讀取、寫入與解析
在 JavaScript 中處理 JSONL(JSON Lines)檔案的完整指南。學習在 Node.js 和瀏覽器中使用內建 API 和熱門套件來讀取、寫入、解析和串流處理 JSONL 資料。
最後更新:2026 年 2 月
為什麼選擇 JavaScript 處理 JSONL?
JavaScript 非常適合處理 JSONL 檔案。JSON 本身就源自 JavaScript,因此該語言透過內建的 JSON.parse() 和 JSON.stringify() 方法提供了一流的解析支援。無論您是建構 Node.js 資料管線、在伺服器上處理日誌檔案,還是讓使用者在瀏覽器中上傳 JSONL,JavaScript 都能為您提供處理每個步驟的工具。
JSONL(JSON Lines)每行儲存一個 JSON 物件,非常適合串流處理、僅附加日誌記錄和逐行處理大型資料集。Node.js 串流與這種格式完美契合,讓您可以讀取和轉換數百萬筆記錄而不會耗盡記憶體。在用戶端,瀏覽器的 FileReader 和 Streams API 可以完全在使用者裝置上進行 JSONL 處理。在本指南中,您將學習如何在 Node.js 和瀏覽器中讀取 JSONL、寫入 JSONL 檔案、建構串流轉換管線,以及為專案選擇合適的 npm 套件。
在 Node.js 中讀取 JSONL
Node.js 提供 readline 模組來高效地逐行讀取檔案。結合 fs.createReadStream,這是在伺服器上處理 JSONL 檔案的推薦方式,因為它以串流方式處理資料,而不是將整個檔案載入記憶體。
使用 fs.createReadStream 導入 readline.createInterface 來逐行讀取 JSONL 檔案。無論檔案大小如何,這種方式都只使用最少的記憶體。
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;}// Usageconst 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 讀取使用者選取的檔案,然後將文字內容按行分割並逐行解析。這確保所有資料都保留在用戶端,保護隱私。
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"> elementconst 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 來逐塊處理檔案。這避免了一次將整個檔案載入記憶體。
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 linefor (const line of lines) {const trimmed = line.trim();if (trimmed) yield JSON.parse(trimmed);}}// Handle remaining bufferif (buffer.trim()) {yield JSON.parse(buffer.trim());}}// Usagefor await (const record of streamJsonl(file)) {console.log(record);}
在 Node.js 中寫入 JSONL
在 Node.js 中寫入 JSONL 檔案非常簡單:將每個 JavaScript 物件序列化為 JSON 字串並附加換行符。對於大型資料集,使用寫入串流而不是在記憶體中建構整個字串,以獲得最佳效能。
使用 fs.writeFileSync 或 fs.createWriteStream 將記錄寫入 JSONL 檔案。每筆記錄是一行有效的 JSON,後面跟著換行符。
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`);
當寫入數百萬筆記錄時,使用可寫入串流來避免在記憶體中建構整個輸出字串。串流會自動處理背壓,當作業系統緩衝區滿時會暫停寫入。
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 backpressureif (!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');}// Usageconst 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 工作、日誌處理和資料遷移。
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 backconst 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 hererecord.processed = true;record.processedAt = new Date().toISOString();callback(null, JSON.stringify(record) + '\n');} catch (err) {callback(err);}},});// Build the pipelineconst 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 工作流程。
JavaScript JSONL 相關套件
雖然內建的 JSON.parse 能處理大多數情況,但有幾個 npm 套件提供了便利的 JSONL 專用工具,如串流處理、驗證和批次處理。
JSON.parse(內建)
內建內建的 JSON.parse() 和 JSON.stringify() 在 V8 中經過高度最佳化,足以應對大多數 JSONL 使用情境。將它們與 readline 結合即可進行串流處理。無需任何依賴,對於數百 MB 以內的檔案效能表現優異。
ndjson
熱門ndjson 是一個熱門的 npm 套件,提供與 Node.js 串流相容的 JSONL(換行分隔 JSON)串流解析器和序列化器。它能優雅地處理解析錯誤,並與現有的串流管線良好整合。非常適合快速原型開發。
jsonl-parse-stringify
簡潔jsonl-parse-stringify 是一個輕量級、零依賴的套件,提供簡單的 parse() 和 stringify() 方法來處理 JSONL 資料。它能處理尾隨換行和空行等邊界情況。當您需要簡潔的同步 API 而不需要設定串流時,這是理想選擇。
試試我們的免費 JSONL 工具
不想寫程式碼?使用我們的免費線上工具,直接在瀏覽器中檢視、轉換和格式化 JSONL 檔案。所有處理都在本機進行,您的資料保持私密。