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 的流(stream)与这种格式完美契合,让您可以读取和转换数百万条记录而不会耗尽内存。在客户端,浏览器的 FileReader 和 Streams API 可以完全在用户设备上处理 JSONL。本指南将介绍如何在 Node.js 和浏览器中读取 JSONL、写入 JSONL 文件、构建流式转换管道,以及如何选择适合项目的 npm 库。

在 Node.js 中读取 JSONL

Node.js 提供了 readline 模块来高效地逐行读取文件。结合 fs.createReadStream,这是在服务器上处理 JSONL 文件的推荐方式,因为它以流式传输数据,而不是将整个文件加载到内存中。

使用 fs.createReadStream 管道到 readline.createInterface 来逐行读取 JSONL 文件。这种方式无论文件大小如何,都只使用极少的内存。

使用 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 字符串并追加换行符。对于大型数据集,使用写入流(write stream)而不是在内存中构建完整字符串可以获得更好的性能。

使用 fs.writeFileSync 或 fs.createWriteStream 将记录写入 JSONL 文件。每条记录是一行有效的 JSON,后面跟一个换行符。

使用 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`);

写入数百万条记录时,使用可写流来避免在内存中构建完整的输出字符串。流会自动处理背压(backpressure),当操作系统缓冲区满时暂停写入。

大数据量的流式写入
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 Stream

Node.js 的 Transform stream 让您可以构建可组合的数据管道:读取 JSONL、处理每条记录、然后写入结果。这种模式非常适合 ETL 任务、日志处理和数据迁移。

JSONL 管道的 Transform Stream
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 stream 自动处理背压,因此即使对于非常大的文件,内存使用也保持恒定。您可以链式连接多个 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 文件。所有处理均在本地完成,您的数据始终保持私密。

在线处理 JSONL 文件

在浏览器中直接查看、验证和转换最大 1GB 的 JSONL 文件。无需上传,100% 私密。

常见问题

JavaScript 处理 JSONL — 在 Node 中读取、写入与流式处理 JSON Lines | jso...