JSON Toolkit

Praktikal fail JSONL: membuka, menukar dan membetulkan baris rosak

Inti pati: Memberikan keseluruhan fail .jsonl kepada JSON.parse dan menerima ralat hampir tidak pernah bermakna fail rosak — ia bermakna strategi bacaan salah. Panduan ini meliputi cara standard memeriksa dan membaca JSONL baris demi baris, arahan penukaran dua hala dengan tatasusunan JSON, jadual enam jenis baris rosak dan cara betul mengguna NDJSON daripada respons HTTP streaming.

Pertengahan~9 min bacaanDiterbitkan 2026-11-06Dikemas kini 2026-11-06
Panduan praktikal membaca fail JSONL baris demi baris dan mengasingkan baris rosak

Kesimpulan: setiap baris fail JSONL ialah nilai JSON sah dan berasingan, tetapi keseluruhan fail bukan satu dokumen JSON tunggal. Jika memberikan keseluruhan fail kepada JSON.parse atau json.load gagal, sembilan daripada sepuluh kali fail itu baik — strategi bacaan anda yang salah.

Satu rekod setiap baris, tiada koma antara baris, tiada tatasusunan luar — JSONL melepaskan "struktur keseluruhan dokumen" untuk mendapatkan penulisan tambahan, pembacaan streaming dan pengasingan kerosakan per baris. Ketiga-tiga kelebihan hanya terbina apabila fail diproses baris demi baris, dan ketiga-tiganya bertukar menjadi ralat pada saat anda cuba menghurai keseluruhan fail sekaligus.

1. Tiga nama, satu format: JSONL, NDJSON, JSON Lines

Pemula kerap menganggap perbezaan nama bermakna perbezaan sintaks. Tidak:

Nama Konteks biasa Sambungan / jenis media
JSON Lines Kejuruteraan data, set data ML (pandas, Spark, Hugging Face) .jsonl
NDJSON API HTTP streaming, data masa nyata .ndjson, application/x-ndjson
JSONL Singkatan santai untuk mana-mana satu —

Mana-mana alat yang membaca satu juga membaca yang lain. Satu-satunya kriteria memilih nama ialah konvensyen ekosistem hilir anda: tulis .jsonl semasa menyediakan set data Hugging Face, tetapkan application/x-ndjson semasa menyajikan API streaming. Fail JSONL yang mudah alih memenuhi tiga peraturan: pengekodan UTF-8 (tanpa BOM), satu nilai JSON lengkap setiap baris, baris dipisahkan dengan \n. Baris baharu penamat di akhir fail amat disyorkan, dan baris kosong bukan rekod yang sah. Butiran protokol dan justifikasi reka bentuk diliputi dalam tinjauan JSON Lines dan NDJSON kami; artikel ini secara ketat tentang apa yang perlu dilakukan apabila fail sudah di tangan.

2. Pemeriksaan: head dahulu, kemudian grep, editor yang terakhir

Klik dua kali fail .jsonl 500 MB untuk membukanya dalam editor ialah kesilapan paling lazim: tiga juta baris teks tambah sorotan sintaks tambah buffer undo akan membekukan hampir semua editor — dan JSON tiada kena mengena. Menghurai dokumen 45 MB mengambil kira-kira 208 ms dalam Node 22; yang tergantung ialah pemaparan. Format berorientasikan baris dicipta untuk alat berasaskan baris kerana rekod bertepatan dengan baris fizikal:

# Ukur skala dahulu: bilangan rekod dan saiz fail, tanpa membaca kandungan
wc -l events.jsonl && du -h events.jsonl

# Lihat rupa satu rekod (sahkan medan dan struktur)
head -n 1 events.jsonl | jq .

# Cari rekod sasaran terus: alat berasaskan baris berfungsi — hak istimewa JSONL
grep '"level":"error"' events.jsonl | head -n 5
tail -n 100 events.jsonl | jq 'select(.latency_ms > 500)'

Perhatikan arahan terakhir: setiap baris keluar dari tail masih nilai JSON berasingan, jadi ia boleh pergi terus ke jq tanpa membina semula tatasusunan. Pendekatan ini berfungsi sama pada fail berbilang gigabait dengan overhed memori hampir sifar — prinsip yang sama dengan mengapa fail JSON besar melambatkan halaman.

3. Tiga corak standard bacaan baris demi baris

Pembacaan baris demi baris mesti mengendalikan tiga perkara: melangkau baris kosong (terutamanya baris baharu penamat), melaporkan ralat dengan nombor baris, dan tidak membiarkan satu baris rosak memusnahkan keseluruhan kerja. Corak standard dalam ketiga-tiga bahasa berpusing pada ketiga-tiga perkara ini.

Python, perpustakaan piawaian sahaja:

import json

with open("events.jsonl", encoding="utf-8") as f:
    for line_number, line in enumerate(f, start=1):
        if not line.strip():          # langkau baris kosong
            continue
        try:
            record = json.loads(line) # huraikan setiap baris secara berasingan
        except json.JSONDecodeError as e:
            print(f"Baris {line_number} gagal: {e}")  # lapor, jangan berhenti
            continue                  # asingkan baris rosak
        handle(record)

Node dengan modul readline terbina dalam, memori malar tidak kira saiz fail:

import fs from "node:fs";
import readline from "node:readline";

const input = fs.createReadStream("events.jsonl", "utf8");
const lines = readline.createInterface({ input, crlfDelay: Infinity });
let lineNumber = 0;
for await (const line of lines) {
  lineNumber += 1;
  if (!line.trim()) continue;
  try {
    handle(JSON.parse(line));
  } catch (e) {
    console.error(`Baris ${lineNumber}: ${e.message}`);
  }
}

Dalam Go 1.27, encoding/json/v2 menjadi piawaian lalai, dan penyahkod strim nilai demi nilai sesuai dengan JSONL; gunakan gojq jika anda perlu membenamkan ungkapan jq. Tentang pustaka, jangan tergesa memasang pakej: jsonlines dalam Python melaporkan nombor dan teks mentah setiap baris bermasalah, dan orjsonl membaca serta menulis fail termampat gzip/bzip2/zstd terus; pakej Node ndjson tidak menerbitkan sebarang keluaran sejak 2020 — readline terbina dalam sudah memadai.

4. Penukaran dua hala dengan tatasusunan JSON

Arah penting; terbalikkan dan setiap arahan akan salah. Ingat satu peraturan: tatasusunan → JSONL ialah map (setiap rekod dimampatkan menjadi satu baris), JSONL → tatasusunan ialah collect (baris dikumpulkan menjadi senarai).

# Tatasusunan JSON → JSONL: -c memampatkan setiap elemen menjadi satu baris
jq -c '.[]' records.json > records.jsonl

# JSONL → tatasusunan JSON: -s mengumpulkan keseluruhan input menjadi satu tatasusunan
jq -s '.' events.jsonl > records.json

# Tapis JSONL baris demi baris: -s tidak perlu, jq memproses input sebagai strim
jq -c 'select(.active == true)' events.jsonl > active.jsonl

Satu baris arahan Python setara: tatasusunan → JSONL menulis json.dumps(r, ensure_ascii=False) + "\n" bagi setiap rekord; arah sebaliknya mengumpulkan hasil json.loads baris demi baris ke dalam senarai. Setiap arah mempunyai satu perangkap. Ke arah pergi (tatasusunan → JSONL), sebarang baris baharu sebenar dalam rekod mesti diloloskan oleh json.dumps — jika tidak, satu rekord akan robek menjadi beberapa baris. Ke arah balik (JSONL → tatasusunan), jangan cantumkan baris menjadi satu rentetan gergasi lalu menghuraikannya — dengan berjuta-juta baris itu satu salinan penuh yang tidak perlu dalam memori. Pengagregatan (jumlah, pengelompokan, purata) memerlukan -s yang memuatkan semuanya; pada fail berbilang GB, beralihlah ke awk atau pengumpul streaming dalam Python.

5. Enam jenis baris rosak dan cara mendiagnosisnya

Hampir setiap ralat JSONL wujud di peringkat baris. Pengesahan baris demi baris dengan pelaporan nombor baris ialah satu-satunya diagnosis boleh dipercayai. Disusun mengikut kekerapan:

Simptom Punca asas Pembetulan
Extra data di hujung baris Koma ditambah antara baris Buang; setiap baris mesti berdiri sendiri
Satu rekord terbelah merentas baris Baris baharu sebenar tidak diloloskan dalam rekod (diformat tangan) Mampatkan semula dengan json.dumps / jq -c
Baris pertama gagal dengan Unexpected token ï Fail mempunyai BOM Simpan semula sebagai UTF-8 tanpa BOM
Hanya baris terakhir beralat, walaupun nampak betul Baris baharu penamat hilang atau ruang berlebihan Tambah \n; langkau baris kosong mengikut konvensyen
Ralat baris baharu dalam rentetan Baris baharu literal dalam rentetan, bukan \n Betulkan penjana; jangan sesekali mencantum rentetan JSON secara manual
Nombor bulat besar berubah nilai Dihurai melalui double (potong pada 2^53) Guna penghurai yang memelihara ketepatan, lihat ketepatan bigint

Rutin diagnosis sentiasa tiga langkah: head -n 1 untuk mengesahkan pengekodan dan struktur baris pertama; jalankan skrip baris demi baris yang melaporkan nombor setiap baris rosak dan bukannya berhenti pada yang pertama; kemudian keluarkan baris rosak satu demi satu — satu baris ialah satu rekord penuh, memeriksanya secara berasingan tidak menelan kos. Untuk import pukal, polisi yang disyorkan ialah "kuarantin, bukan hentikan": tulis baris rosak berserta nombornya ke errors.jsonl, teruskan memuatkan rekod yang baik, kemudian tentukan keputusan import semula berdasarkan kadar baris rosak.

6. JSONL atas HTTP: penggunaan baris demi baris dan backpressure

Corak tipikal NDJSON atas HTTP ialah pelayan menulis berterusan dan klien mengguna berterusan. Di pihak klien, jangan panggil response.json() — ia menampung keseluruhan badan sebelum penghuraian, menghapuskan makna streaming. Baca strim badan secara langsung, pisahkan pada \n dan bawa mana-mana serpihan hujung yang belum lengkap ke lelaran seterusnya:

const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
let buffer = "";
for (;;) {
  const { value, done } = await reader.read();
  if (done) break;
  buffer += value;
  const lines = buffer.split("\n");
  buffer = lines.pop();               // cebisan terakhir mungkin baris tak lengkap
  for (const line of lines) {
    if (line.trim()) handle(JSON.parse(line));
  }
}

Di pihak pelayan dua perkara wajib: pertama, apabila res.write() memulangkan false, tunggu acara drain (backpressure), jika tidak memori berkembang tanpa batas setiap kali pengguna lebih lambat daripada pengeluar; kedua, lumpuhkan middleware gzip pada laluan streaming — gzip mesti menampung keseluruhan respons sebelum dapat memampatkan apa-apa, dan itu melumpuhkan streaming NDJSON sepenuhnya. Kedua-dua tingkah laku disahkan melalui ujian setempat dan beberapa sumber bebas berbahasa Inggeris, bukan sangkaan.

7. Bilakah JSONL bukan pilihan yang tepat

Ruang negatif pemilihan format juga penting. Tiga senario patut kekal dengan tatasusunan JSON:

Keperluan Mengapa JSONL kurang sesuai Guna sebaliknya
Mengesahkan struktur keseluruhan dokumen Tiada struktur keseluruhan; sisihan medan tidak disedari Tatasusunan JSON + Schema
Akses rawak ke rekod ke-N Panjang baris berubah-ubah; carian binari tidak boleh SQLite / Parquet
Sarangan dalam, rujukan merentas rekod Setiap baris berasingan; rujukan tiada tempat tinggal Dokumen JSON piawai

Peraturan ibu jari dalam satu ayat: jika rekod tiba dari semasa ke semasa atau digunakan baris demi baris (log, acara, eksport, set latihan), gunakan JSONL; jika volum kecil dihasilkan sekali, digunakan sekali dan memerlukan semantik dokumen penuh, gunakan tatasusunan JSON. Varian terbitan (JSON Text Sequences dengan pemisah RS) ialah topik lain — lihat artikel RFC 7464.

FAQ

Adakah terdapat perbezaan sebenar antara JSONL dan NDJSON?

Dari segi kejuruteraan, tidak. Kedua-duanya bermaksud "satu nilai JSON lengkap setiap baris, tiada pembalut luaran, tiada koma antara baris", dan mana-mana alat yang menyokong satu turut menyokong yang lain. Perbezaan adalah pada penamaan dan tabiat ekosistem: .jsonl menguasai kejuruteraan data dan set data ML; .ndjson dan application/x-ndjson menguasai API HTTP streaming. Semasa berintegrasi dengan sistem luaran, ikuti sambungan dan jenis media yang ditetapkan dalam dokumentasinya.

Bolehkah saya membaca fail .jsonl terus dengan JSON.parse?

Bukan keseluruhan fail. JSON.parse menerima tepat satu teks JSON, manakala JSONL ialah banyak nilai berasingan disusun baris demi baris, jadi penghuraian keseluruhan fail sentiasa gagal dengan "Unexpected token" atau "Extra data". Pecahkan kepada baris dan huraikan setiap baris tidak kosong secara berasingan, melaporkan nombor baris apabila gagal.

Jika satu baris fail JSONL rosak, adakah keseluruhan fail musnah?

Tidak — pengasingan kerosakan baris demi baris ialah teras reka bentuk format ini. Baris rosak hanya memberi kesan kepada dirinya sendiri: langkau, catat nombornya dan teruskan membaca. Untuk import pukal, kuarantin baris rosak ke dalam fail berasingan, muatkan rekod yang baik seperti biasa, kemudian tentukan pembetulan dan import semula berdasarkan kadar baris rosak.

Bagaimana menukar JSONL kepada Excel atau CSV?

Mula-mula jadikan ia tatasusunan atau ekstrak medan baris demi baris, kemudian jalankan penukaran jadual: mampatkan dengan jq -c '.[]' data.jsonl dan serahkan kepada penukar, atau paipkan setiap baris melalui json.loads ke pandas. Berhati-hati: medan bersarang yang diratakan menghasilkan nama lajur bertitik, medan tatasusunan hanya boleh disirikan sebagai teks dalam sel, dan lajur ID panjang patut diisytiharkan sebagai rentetan seawal mungkin untuk mengelakkan kehilangan ketepatan.

Rujukan

Alat sepadan

Artikel berkaitan

JSON Lines dan NDJSON: Data Penstriman

Satu nilai JSON per baris membeli kebolehtambahan, penstriman dan kerosakan terpencil pada satu baris; kosnya ialah ketiadaan struktur keseluruhan, jadi pengesahan mesti dilakukan baris demi baris.

Pertengahan~10 min bacaanDikemas kini 2026-10-30

Jujukan Teks JSON (RFC 7464): JSON Penstriman Berdelimit RS

RFC 7464 menggunakan pemisah 0x1E untuk menstrim teks JSON yang boleh anda baca dan tulis sekali gus. Meliputi peraturan, cara ia berbeza daripada NDJSON, dan pelaksanaan pisah-kemudian-huraikan.

Pertengahan~9 min bacaanDikemas kini 2026-10-31

Menghurai, Memaparkan, dan Menstrim JSON Besar

Penghuraian selalunya bukan kesesakan; pemaparan dan penyalinan ialah. Optimumkan sepanjang empat lapisan "hurai → telusuri → paparkan → hantar" supaya usaha anda tidak terbuang.

Pertengahan~13 min bacaanDikemas kini 2026-10-31