Duży plik JSON się nie otwiera: wybierz odpowiednie narzędzie według rozmiaru
Podsumowanie: Eksporty JSON w dziesiątkach MB często zawieszają edytory tekstu i narzędzia online, podczas gdy sam parsing zajmuje kilkaset milisekund. Zmierzyliśmy czas i pamięć na każdym etapie dla próbki 45 MB i 500 000 rekordów, pokazaliśmy, że prawdziwym kosztem jest liczba linii i węzłów, i ułożyliśmy tabelę doboru narzędzi według rozmiaru pliku: podgląd online, wiersz poleceń, przetwarzanie strumieniowe i aplikacja desktopowa.

Plik JSON o rozmiarze 45 MB parsuje się w 249 milisekund. Pół minuty czekania pochodzi z renderowania pięciu milionów linii tekstu i 3,5 miliona węzłów drzewa. Kto pomyli te dwie rzeczy, zawsze szuka winnego w niewłaściwym miejscu.
Jeden: najpierw zmierz — parsing nigdy nie jest wąskim gardłem
Podwójne kliknięcie na eksport JSON w dziesiątkach MB, edytor kręci się przez trzydzieści sekund, a odruch mówi „parsowanie JSON jest wolne". Pomiary mówią co innego. Na naszej maszynie (Node 22) wygenerowaliśmy próbkę 500 000 rekordów po pięć pól (id, email, active, score, tags), 45 MB w formie zwartej:
| Operacja | Zmierzony wynik |
|---|---|
Pełne JSON.parse |
249 ms |
JSON.stringify(data, null, 2) — sformatowane wyjście |
215 ms |
| Sformatowany tekst | 71 MB, 5 000 001 linii |
| Węzły drzewa łącznie (rekordy + pola) | około 3 500 001 |
| RSS procesu Node po parsowaniu | 313 MB (mniej więcej 7× rozmiaru pliku) |
Parsowanie skończyło się w jedną czwartą sekundy. Parser skończył pracę, zanim puściłeś mysz. Wszystkie następne sekundy poszły na warstwę „pokazać wynik człowiekowi": edytor tekstu musi złożyć pięć milionów linii, nałożyć podświetlanie składni i utrzymać bufor cofania; podgląd drzewa musi stworzyć element DOM dla każdego z 3,5 miliona węzłów — a przeglądarki potykają się koło stu tysięcy węzłów i tracą responsywność długo przed milionem.
Wniosek wskazuje zupełnie innym kierunkiem: nie walcz z renderowaniem — weź narzędzie, które nie renderuje wszystkiego naraz.
Dwa: dlaczego się zawiesza — liczba linii i węzłów to prawdziwy koszt
Rozmiar pliku to tylko powierzchnia. Narzędzia łamią dwie pochodne liczby:
- Liczba linii. 45 MB zwartego JSON po formatowaniu to pięć milionów linii. Na którąkolwiek część nie patrzysz, edytor musi najpierw zbudować strukturę linii całego pliku, rozstrzygnąć stan podświetlenia i przydzielić bufory — koszty proporcjonalne do łącznej liczby linii.
- Liczba węzłów. Pół miliona rekordów × (jeden obiekt + pięć pól) to 3,5 miliona węzłów. Każda przeglądarka, która buduje całe drzewo przed pokazaniem, płaci tę samą pamięć i czas — czy rozwijasz jedną gałąź, czy wszystkie.
Stąd dwa nieintuicyjne wnioski. Formatowanie przed obejrzeniem szkodzi — plik rośnie z 45 do 71 MB, a liczba linii mnoży się czterdziestokrotnie, czysto dodatkowa presja na narzędzie. Wpychanie pliku przez cat do terminala też szkodzi — bufor przewijania staje się nowym wąskim gardłem; na pierwsze bajty wystarczy head -c 2000.
Trzy: dobrać narzędzie według rozmiaru — tabela decyzyjna
Różnym rozmiarom odpowiadają zupełnie różne narzędzia. Łącząc pomiary powyżej z opublikowanymi wskazówkami (OpenFormatter stawia strefę komfortu narzędzi online na 2-5 MB; PureJSON szacuje pamięć po parsowaniu dokumentu 500 MB na 2-4 GB), powstaje taka tabela:
| Rozmiar pliku | Pierwszy wybór | Dlaczego |
|---|---|---|
| < 2 MB | Dowolne narzędzie online | Natychmiastowy dostęp; podgląd drzewa + walidacja à la /parse jednym krokiem |
| 2 – 20 MB | Lokalny edytor (VS Code) albo lokalne narzędzie w przeglądarce | Narzędzia online zaczynają degradować; przetwarzanie lokalne nic nie wysyła |
| 20 – 100 MB | Rozpoznanie przez jq w CLI + zwirtualizowany podgląd drzewa | Edytory zaczynają przycinać; jq wyciąga dowolny fragment w sekundy |
| 100 MB – 1 GB | jq --stream / ijson, przetwarzanie strumieniowe |
Pamięć konwencjonalnego parsowania rośnie do ~7× rozmiaru pliku; się nie mieści — strumieniuj |
| > 1 GB lub ciągłe dopisywanie | Zmienić format: NDJSON / CSV / Parquet | Jedno gigantyczne tablice trzeba sparsować w całości, zanim pierwszy rekord stanie się użyteczny; problem już leży w formacie |
Narzędzie /parse na tej stronie pokrywa pierwszy stopień: podgląd drzewa i walidację. Większe pliki należą do aplikacji desktopowej, żeby dziesiątki MB nigdy nie trafiały do strony WWW.
Cztery: nie otwieraj pliku — najpierw zapytaj o strukturę
Wobec nieznanego dużego JSON pierwszym ruchem nie jest otwarcie, lecz kilka sekund na rozpoznanie kształtu. jq odpowiada na trzy pytania w około 200 ms:
# U góry tablica czy obiekt? Ile rekordów?
jq 'if type == "array" then {type: "array", count: length} else {type: "object", keys: (keys|length)} end' huge.json
# Jak wygląda pierwszy rekord (jeden, bez potopu)?
jq '.[0]' huge.json | head -40
# Wszystkie nazwy pól (z pierwszego rekordu)
jq '.[0] | keys' huge.json
Gdy struktura znana, większość żądań redukuje się do „wyciągnij pole" — plik w ogóle nie musi być otwierany. Na przykład potrzebujesz maila każdego użytkownika:
jq -r '.[].email' huge.json | less
# Nałóż filtr
jq -r '.[] | select(.active == true) | .email' huge.json
Reguła prosta: na „oglądanie" — przeglądarka ze zwirtualizowanym renderowaniem; na „szukanie i wyciąganie" — jq. Nie mieszaj obu ról w jednym narzędziu.
Pięć: urwisko pamięci — tryb zwykły kontra strumieniowy, różnica 150×
Na tej samej próbce 45 MB /usr/bin/time -v zmierzył szczytową pamięć jq w dwóch trybach:
| Tryb | Polecenie | Szczyt pamięci (RSS) | Czas |
|---|---|---|---|
| Zwykły (pełne wczytanie) | jq '.[0].email' sample.json |
542 MB | 0,7 s |
| Strumieniowy | jq --stream 'select(.[0][1]=="email") | .[1]' sample.json |
3,6 MB | 2,5 s |
Tryb zwykły czyta cały plik i buduje graf obiektów; szczyt 542 MB potwierdza regułę „graf obiektów ≈ 7-12× rozmiaru tekstu". --stream konsumuje wejście token po tokenie, trzymając pamięć w granicach pojedynczych MB — kosztem dłuższego czasu całkowitego. Za gigabajtem ta różnica oddziela „działa" od „zabity przez OOM killer":
# Dla plików większych niż pamięć: --stream to jedyny tryb, który nigdy nie wczytuje wszystkiego
jq --stream -n 'fromstream(1|truncate_stream(inputs))' huge.json
Pythonowy odpowiednik to ijson: ijson.items(f, 'item') oddaje elementy tablicy po jednym przy tej samej stałej pamięci. Wspólna cena tych narzędzi: rezygnacja z dostępu losowego — strumień to jeden przebieg naprzód, a drugi przebieg oznacza ponowne czytanie pliku.
Sześć: ile pokaże przeglądarka — granice lokalnego przetwarzania
Narzędziami online można się posługiwać, w granicach. Nowoczesna karta przeglądarki ma około 1-4 GB pamięci; plik 45 MB sparsowany do grafu plus drzewo zwykle przetrwa. Kilka set MB to już skraj urwiska. Wybierając przeglądarkę online, wymagaj trzech rzeczy:
- Przetwarzanie dzieje się lokalnie (wklejona treść nigdy nie trafia na serwer) — chroni to dane i oszczędza czas wysyłania; wszystkie narzędzia tej strony działają w całości w przeglądarce i są dostępne offline;
- Parsing działa w Web Workerze — główny wątek nie zamarza, a zawieszenie kosztuje kartę, nie cały przeglądarkę;
- Drzewo jest zwirtualizowane albo leniwe — zwinięte gałęzie prawie nic nie kosztują, renderuje się tylko rozwinięte.
Na tej stronie: /parse nadaje się do rozpoznania struktury i lokalizacji błędów w plikach do kilkudziesięciu MB; wyżej — jq albo aplikacja desktopowa, przeglądarka zostaje dla małych fragmentów.
Siedem: właściwy format usuwa połowę problemów
Jeśli wpływasz na to, jak plik powstaje, lepsza przeglądarka to niewłaściwe lekarstwo — dopilnuj, żeby nie urastał do „jednej gigantycznej tablicy":
- NDJSON/JSONL: jeden rekord na linię. Dopisywanie nie przepisuje pliku, a
head,grep,tail,splitdziałają bezpośrednio; ucięty plik traci tylko ostatnią linię. W naszym podręczniku JSONL jest pełna procedura rozbierania połamanych linii. - Eksporty stronicowane: API zwracające 100 000 rekordów powinno przyjmować parametry stronicowania — po 100 naraz to wygodniejsze dla obu stron.
- Dane tabelaryczne to nie JSON: jeden rekord na linię, stałe pola bez zagnieżdżenia — to tabela. CSV albo Parquet są mniejsze i mają bogatsze ekosystemy.
Liczba do zapamiętania: przetnij na pół tablicę z 500 000 rekordów — pierwsza połowa pozostaje ważnym plikiem NDJSON (połowa rekordów przeżywa), podczas gdy odpowiadająca pojedyncza gigantyczna tablica ginie w całości. 500 uratowanych rekordów z 501 to więcej niż zero.
Osiem: checklista
- Najpierw rozpoznaj strukturę przez
jq '.[0] | keys'albo próbkę 500 rekordów; - Nigdy nie formatuj tylko po to, żeby otworzyć plik — podwojenie linii tylko go spowolni;
- Poniżej 2 MB: online podgląd drzewa; powyżej 20 MB: wiersz poleceń; powyżej 1 GB: zawsze
--streamalbo ijson; - Sprawdź, że narzędzie online przetwarza lokalnie (wklejona treść nie opuszcza przeglądarki);
- Jeśli kontrolujesz generator — przejdź na NDJSON lub stronicowanie i usuń gigantyczne tablice u źródła.
FAQ
Dlaczego edytor otwiera JSON dziesiątki sekund, skoro program parsuje go w 200 ms?
Parsowanie to kod natywny zamieniający tekst w strukturę danych: 249 ms na naszej próbce 45 MB. Edytor zgrzyta na prezentacji: pięć milionów linii do złożenia, podświetlenia i bufora cofania; drzewo buduje DOM dla 3,5 miliona węzłów. Zwirtualizowana przeglądarka albo bezpośrednie wyciąganie przez jq omija to wszystko.
Czy jq przepełni pamięć przy JSON powyżej 1 GB?
W trybie zwykłym tak: wczytuje cały dokument, a graf obiektów sięga szczytu 7-12× rozmiaru pliku. Z --stream wejście jest konsumowane token po tokenie: nasz test 45 MB doszedł szczytu 3,6 MB, a pamięć pozostaje płaska niezależnie od rozmiaru — kosztem jedynego sekwencyjnego przebiegu.
Jak duże pliki udźwigną narzędzia JSON online?
Większość jest komfortowa do 2-5 MB i wyraźnie się pogarsza po 10 MB. Twardy sufit to pamięć karty (około 1-4 GB), ale już przy kilkudziesięciu MB czekanie na parsowanie i budowę drzewa boli. Powyżej 20 MB sięgnij po narzędzie lokalne albo wiersz poleceń.
Jak obejrzeć wartość jednego pola w ogromnym JSON?
Wyciągnij przez jq bez otwierania pliku: jq -r '.[].email' huge.json wypisze wszystkie maile; z filtrem — jq -r '.[] | select(.active == true) | .email'. Pierwsze rekordy: jq '.[0:5]' huge.json — o rzędy wielkości szybciej niż otwieranie.
Czy formatowanie przed otwarciem pomaga?
Nie. Formatowanie zamienia zwarte 45 MB w 71 MB i jedną linię w pięć milionów, dokładając czysty balast edytorowi i przeglądarce. Formatuj tylko to, co ma przeczytać człowiek — i tylko gdy plik jest dostatecznie mały.