Kompletny przewodnik NDJSON: Wyjaśnienie Newline Delimited JSON
Kompleksowy przewodnik po Newline Delimited JSON (NDJSON). Poznaj specyfikację, typ MIME, jak czytać i pisać NDJSON w Python, Node.js i wierszu poleceń, używać go w strumieniowych API HTTP i zrozumieć jego relację z JSONL.
Ostatnia aktualizacja: luty 2026
Czym jest NDJSON?
NDJSON to skrót od Newline Delimited JSON. Jest to tekstowy format danych, w którym każda linia zawiera dokładnie jedną prawidłową wartość JSON, oddzieloną znakiem nowej linii (\n). Format został zaprojektowany do strumieniowania i przetwarzania dużych zbiorów danych bez ładowania całego pliku do pamięci. W przeciwieństwie do standardowego pliku JSON, który opakowuje wszystko w jedną tablicę lub obiekt, NDJSON pozwala czytać, pisać i przetwarzać rekordy jeden po drugim.
Specyfikacja NDJSON jest hostowana na github.com/ndjson/ndjson-spec. Została stworzona, aby sformalizować wzorzec, który stał się już powszechny w przesyłaniu logów, potokach danych i strumieniowych API HTTP. Każda linia jest samodzielna: jeśli jedna linia zawiera nieprawidłowy JSON, inne linie mogą być nadal pomyślnie sparsowane. Sprawia to, że NDJSON jest odporny na błędy i dobrze przystosowany do przepływów pracy opartych na dopisywaniu, takich jak logi aplikacji, strumienie zdarzeń i przyrostowe eksporty danych.
{"id":1,"event":"page_view","url":"/home"}{"id":2,"event":"click","url":"/pricing"}{"id":3,"event":"signup","url":"/register"}
Specyfikacja NDJSON
Oficjalna specyfikacja NDJSON na github.com/ndjson/ndjson-spec jest celowo minimalistyczna. Definiuje prostą konwencję serializacji wielu wartości JSON w jednym strumieniu tekstowym. Podstawowe zasady są proste:
Specyfikacja celowo unika dodawania nagłówków, metadanych lub informacji o schemacie do formatu. Dzięki temu NDJSON jest tak prosty, jak to możliwe, i kompatybilny ze standardowymi narzędziami uniksowymi do przetwarzania tekstu. Każda prawidłowa wartość JSON jest dozwolona w każdej linii, chociaż w praktyce większość plików NDJSON zawiera obiekty JSON ze spójnym zestawem kluczy.
- Każda linia MUSI zawierać dokładnie jedną prawidłową wartość JSON (obiekt, tablicę, ciąg znaków, liczbę, wartość logiczną lub null).
- Linie są oddzielane znakiem nowej linii '\n' (U+000A). Znak powrotu karetki '\r' (U+000D) może pojawić się przed '\n', ale nie jest wymagany.
- Końcowy znak nowej linii po ostatniej wartości JSON jest dozwolony, ale nie wymagany.
- Każda wartość JSON nie może zawierać niezamaskowanych znaków nowej linii wewnątrz samej wartości.
Ponieważ zasady są minimalne, NDJSON jest łatwy do wygenerowania z dowolnego języka programowania, który posiada serializator JSON. Wystarczy serializować każdy rekord, dopisać znak nowej linii i zapisać do wyjścia. Żadnych zamykających nawiasów, żadnych końcowych przecinków, żadnej otaczającej struktury tablicy do zarządzania.
NDJSON vs JSON vs JSONL
NDJSON, JSON i JSONL mają różną strukturę. Standardowy JSON koduje jedną wartość (zwykle tablicę lub obiekt). JSONL i NDJSON przechowują jedną wartość JSON na linię i są funkcjonalnie identyczne. Poniższa tabela przedstawia kluczowe różnice między wszystkimi trzema formatami.
| Cecha | JSON | JSONL | NDJSON |
|---|---|---|---|
| Pełna nazwa | JavaScript Object Notation | JSON Lines | Newline Delimited JSON |
| Rozszerzenie pliku | .json | .jsonl | .ndjson |
| Typ MIME | application/json | application/jsonl (nieoficjalny) | application/x-ndjson |
| Specyfikacja | RFC 8259 (standard IETF) | jsonlines.org (społeczność) | github.com/ndjson/ndjson-spec (społeczność) |
| Separator linii | Nie dotyczy (pojedyncza wartość) | \n (nowa linia) | \n (nowa linia) |
| Końcowy znak nowej linii | Nie dotyczy | Zalecany | Opcjonalny |
| Przyjazny strumieniowaniu | Nie (trzeba sparsować cały dokument) | Tak (linia po linii) | Tak (linia po linii) |
Typ MIME NDJSON: application/x-ndjson
Zarejestrowany typ MIME dla NDJSON to application/x-ndjson. Ten typ zawartości jest używany w nagłówkach HTTP, aby wskazać, że treść odpowiedzi zawiera dane JSON rozdzielane znakami nowej linii. Wiele strumieniowych API, w tym GitHub API, Docker Registry API i Elasticsearch bulk API, używa tego typu MIME do dostarczania odpowiedzi NDJSON.
Content-Type: application/x-ndjson# Example: curl a streaming APIcurl -H "Accept: application/x-ndjson" https://api.example.com/events/stream# Example: Express.js responseres.setHeader('Content-Type', 'application/x-ndjson');res.write(JSON.stringify(record) + '\n');
Niektóre API akceptują również application/json-seq (RFC 7464) lub text/plain jako alternatywy. Jednak application/x-ndjson jest najszerzej przyjętym typem MIME dla strumieni JSON rozdzielanych znakami nowej linii. Budując nowe API strumieniujące rekordy JSON, użyj application/x-ndjson dla maksymalnej kompatybilności.
Odczyt i zapis NDJSON
Praca z NDJSON jest prosta w każdym języku obsługującym JSON. Poniżej znajdują się praktyczne przykłady dla Python, Node.js i wiersza poleceń.
Wbudowany moduł json w Python naturalnie obsługuje NDJSON. Czytaj linie z pliku, parsuj każdą za pomocą json.loads i zapisuj za pomocą json.dumps. Dla dużych plików to podejście linia po linii zużywa stałą ilość pamięci.
guide-ndjson-complete-guide.ndjsonGuide.readWrite.python.code
W Node.js użyj modułu readline z fs.createReadStream do efektywnego parsowania plików NDJSON. Strumień przetwarza jedną linię na raz, utrzymując niskie zużycie pamięci niezależnie od rozmiaru pliku.
import { createReadStream, writeFileSync } from 'node:fs';import { createInterface } from 'node:readline';// Read NDJSONasync function readNdjson(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;}// Write NDJSONconst data = [{ id: 1, event: 'page_view' },{ id: 2, event: 'click' },];const ndjson = data.map(r => JSON.stringify(r)).join('\n') + '\n';writeFileSync('output.ndjson', ndjson, 'utf-8');
Narzędzie wiersza poleceń jq natywnie rozumie dane wejściowe NDJSON. Użyj flagi --slurp, aby zebrać wszystkie rekordy w tablicę, lub przetwarzaj każdy rekord indywidualnie bez żadnej flagi.
# Print each record (jq reads NDJSON by default)jq '.' data.ndjson# Filter records where event is "click"jq 'select(.event == "click")' data.ndjson# Extract specific fieldsjq {id, url} data.ndjson# Count total recordsjq -s 'length' data.ndjson# Convert NDJSON to a JSON arrayjq -s '.' data.ndjson > data.json# Convert a JSON array back to NDJSONjq -c '.[]' data.json > data.ndjson
NDJSON w strumieniowych API HTTP
NDJSON jest de facto standardem dla strumieniowych API HTTP dostarczających dane w czasie rzeczywistym. Gdy serwer wysyła odpowiedź NDJSON, klient może rozpocząć przetwarzanie pierwszego rekordu, gdy tylko dotrze, bez czekania na zakończenie całej odpowiedzi. Jest to szybsze i bardziej wydajne pamięciowo niż zwracanie dużej tablicy JSON.
Popularne usługi używające strumieniowania NDJSON to Docker Registry (zdarzenia warstw obrazów), Elasticsearch (operacje masowe), Apache CouchDB (feed zmian) oraz wiele nowoczesnych API sterowanych zdarzeniami. Ten wzorzec dobrze działa z alternatywami Server-Sent Events, śledzeniem logów w czasie rzeczywistym i progresywnym ładowaniem danych w aplikacjach webowych.
import express from 'express';const app = express();app.get('/api/events/stream', (req, res) => {res.setHeader('Content-Type', 'application/x-ndjson');res.setHeader('Transfer-Encoding', 'chunked');// Simulate streaming eventslet id = 0;const interval = setInterval(() => {id++;const event = {id,type: 'heartbeat',timestamp: new Date().toISOString(),};res.write(JSON.stringify(event) + '\n');if (id >= 100) {clearInterval(interval);res.end();}}, 100);req.on('close', () => clearInterval(interval));});app.listen(3000);
async function* readNdjsonStream(url) {const response = await fetch(url, {headers: { 'Accept': 'application/x-ndjson' },});const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();let buffer = '';while (true) {const { done, value } = await reader.read();if (done) break;buffer += value;const lines = buffer.split('\n');buffer = lines.pop();for (const line of lines) {if (line.trim()) yield JSON.parse(line);}}if (buffer.trim()) yield JSON.parse(buffer);}// Usagefor await (const event of readNdjsonStream('/api/events/stream')) {console.log('Received:', event);}
Narzędzia ekosystemu NDJSON
Rosnący ekosystem narzędzi wiersza poleceń i bibliotek obsługuje NDJSON natywnie. Te narzędzia pozwalają filtrować, przekształcać i analizować dane NDJSON bez pisania własnego kodu.
jq
Niezbędnyjq to najpopularniejszy procesor JSON wiersza poleceń. Domyślnie czyta NDJSON (jedna wartość JSON na linię) i obsługuje filtrowanie, mapowanie, grupowanie i przeformatowywanie. Użyj jq -c dla kompaktowego wyjścia i jq -s, aby zebrać wszystkie rekordy w tablicę.
ndjson-cli
CLIndjson-cli to kolekcja poleceń w stylu Unix do manipulowania strumieniami NDJSON: ndjson-filter, ndjson-map, ndjson-reduce, ndjson-sort i ndjson-join. Każde polecenie czyta ze stdin i pisze na stdout, co czyni je komponowalnymi z potokami.
ndjson (npm)
Node.jsPakiet npm ndjson udostępnia strumieniowe parsery i serializatory NDJSON dla Node.js. Oferuje strumienie transformacyjne ndjson.parse() i ndjson.stringify(), które integrują się bezpośrednio z potokami strumieni Node.js do wysokowydajnego przetwarzania danych.
NDJSON i JSONL: Interoperacyjność
NDJSON i JSONL (JSON Lines) to funkcjonalnie identyczne formaty. Oba przechowują jedną wartość JSON na linię, oddzieloną znakami nowej linii. Plik, który jest prawidłowym NDJSON, jest również prawidłowym JSONL i odwrotnie. Możesz zmienić nazwę pliku .ndjson na .jsonl (lub odwrotnie) bez zmiany ani jednego bajta zawartości, a każde narzędzie czytające jeden format odczyta również drugi.
Jedyne różnice są kosmetyczne: NDJSON pochodzi z github.com/ndjson/ndjson-spec i używa rozszerzenia .ndjson z typem MIME application/x-ndjson, podczas gdy JSONL pochodzi z jsonlines.org i używa rozszerzenia .jsonl. W praktyce większość programistów traktuje te dwie nazwy jako synonimy. Jeśli Twój projekt już używa JSONL, nie ma potrzeby migracji do NDJSON, a jeśli biblioteka mówi, że obsługuje NDJSON, będzie działać z Twoimi plikami .jsonl bez żadnych zmian.
Wypróbuj nasze bezpłatne narzędzia NDJSON/JSONL
Pracuj z plikami NDJSON i JSONL bezpośrednio w przeglądarce. Całe przetwarzanie odbywa się lokalnie, więc Twoje dane pozostają prywatne.