CSV i JSON to prawdopodobnie dwa najczęściej spotykane formaty danych jako programista. Pliki CSV pojawiają się w eksportach arkuszy kalkulacyjnych, zrzutach baz danych i pipeline'ach nauki o danych. JSON jest wszędzie w sieci — REST API, pliki konfiguracyjne, bazy danych NoSQL. Oba są zwykłym tekstem, oba są czytelne dla człowieka i oba wykonują zadanie. Ale są zbudowane dla różnych kształtów danych i wybranie niewłaściwego tworzy prawdziwe bóle głowy. Ten artykuł omawia główne różnice, pokazuje konkretne przykłady, gdzie każdy format błyszczy (i zawodzi), i daje praktyczny przewodnik decyzyjny do wyboru między nimi.

Podstawowa różnica: tabele vs drzewa

CSV — zdefiniowany w RFC 4180 — to płaski, tabelaryczny format. Każdy wiersz ma te same kolumny, każda wartość jest ciągiem. To wszystko. Idealnie mapuje się na arkusz kalkulacyjny lub tabelę bazy danych: wiersze w dół, kolumny w poprzek.

JSON — określony w RFC 8259 i opisany na json.org — to format hierarchiczny. Wartości mogą być obiektami, tablicami, ciągami, liczbami, wartościami logicznymi lub null. Obiekty zagnieżdżają się wewnątrz obiektów, tablice zawierają różne kształty. Mapuje się na to, jak dane faktycznie żyją w kodzie — rekordy z relacjami, listy różnych rzeczy, typowane wartości.

Jedno zdanie podsumowania: CSV to tabela. JSON to drzewo. Jeśli Twoje dane są tabelą, CSV jest prostszy i mniejszy. Jeśli Twoje dane mają jakiekolwiek zagnieżdżenie, CSV albo straci informacje, albo zmusi Cię do bolesnych obejść.

Te same dane w obu formatach

Tu różnica staje się konkretna. Wyobraź sobie katalog produktów dla sklepu e-commerce. Produkty mają nazwę, cenę i czy są w magazynie — prosto. Ale mają też warianty (rozmiary, kolory) i atrybuty (materiał, waga). Zobaczmy, jak te dane wyglądają w obu formatach.

W JSON jest to naturalne:

json
[
  {
    "id": "SHOE-001",
    "name": "Trail Runner Pro",
    "price": 129.99,
    "inStock": true,
    "attributes": {
      "material": "mesh",
      "weightGrams": 280
    },
    "variants": [
      { "size": 9,  "color": "black", "sku": "TR-9-BLK",  "qty": 12 },
      { "size": 9,  "color": "white", "sku": "TR-9-WHT",  "qty": 4  },
      { "size": 10, "color": "black", "sku": "TR-10-BLK", "qty": 7  }
    ]
  },
  {
    "id": "SHOE-002",
    "name": "City Walker",
    "price": 89.99,
    "inStock": true,
    "attributes": {
      "material": "leather",
      "weightGrams": 340
    },
    "variants": [
      { "size": 8,  "color": "brown", "sku": "CW-8-BRN",  "qty": 6  },
      { "size": 9,  "color": "brown", "sku": "CW-9-BRN",  "qty": 15 }
    ]
  }
]

Teraz spróbuj umieścić to w CSV. Masz dwie opcje, obie niezręczne. Opcja pierwsza: spłaszcz wszystko i powtarzaj dane nadrzędne dla każdego wiersza wariantu:

csv
product_id,product_name,price,inStock,material,weightGrams,variant_size,variant_color,sku,qty
SHOE-001,Trail Runner Pro,129.99,true,mesh,280,9,black,TR-9-BLK,12
SHOE-001,Trail Runner Pro,129.99,true,mesh,280,9,white,TR-9-WHT,4
SHOE-001,Trail Runner Pro,129.99,true,mesh,280,10,black,TR-10-BLK,7
SHOE-002,City Walker,89.99,true,leather,340,8,brown,CW-8-BRN,6
SHOE-002,City Walker,89.99,true,leather,340,9,brown,CW-9-BRN,15

Nazwa produktu, cena i atrybuty są powtarzane dla każdego wariantu. To redundancja danych — nie wielki problem dla pięciu wierszy, ale dla katalogu 50 000 produktów z 8 wariantami każdy, kumuluje się. Opcja druga: serializuj warianty jako ciąg JSON wewnątrz kolumny CSV — ale teraz osadzasz JSON wewnątrz CSV, aby obejść ograniczenia CSV, co jest code smell, jeśli kiedykolwiek widziałem.

Gdzie wygrywa CSV

Pomimo tego ograniczenia, CSV jest naprawdę lepszym wyborem w kilku powszechnych scenariuszach.

  • Arkusze kalkulacyjne i narzędzia BI. Excel, Google Sheets, Tableau, Looker, Power BI — wszystkie otwierają CSV natywnie jednym kliknięciem. Bez kreatora importu, bez schematu do zdefiniowania, bez kroku transformacji. Jeśli Twoi interesariusze żyją w arkuszach kalkulacyjnych, CSV to ścieżka najmniejszego oporu.
  • Czysto płaskie dane. Jeśli Twoje dane są naprawdę tabelą — zdarzenia analityczne, dzienniki transakcji, odczyty czujników, eksport użytkowników — CSV jest mniejszy i prostszy. Bez powtarzających się kluczy, bez nawiasów, bez szumu.
  • Import/eksport bazy danych. Każda baza danych SQL ma polecenie COPY FROM CSV lub odpowiednik. To standardowy format wymiany dla masowego ładowania danych i jest o rzędy wielkości szybszy niż instrukcje INSERT.
  • pandas i nauka o danych. pandas.read_csv() jest jedną z najczęściej używanych funkcji w Pythonie. Cały ekosystem — NumPy, scikit-learn, Polars — traktuje CSV jako format wejściowy pierwszej klasy.
  • Rozmiar pliku dla dużych płaskich tabel. Bez nazw kluczy w każdym wierszu, CSV jest mniejszy dla szerokich tabel z wieloma wierszami. Milion wierszy CSV zdarzeń analitycznych z łatwością pobije równoważną tablicę JSON.

Gdzie wygrywa JSON

  • Zagnieżdżone i hierarchiczne dane. Gdy tylko Twoje dane mają jakąkolwiek strukturę wykraczającą poza płaską tabelę — zagnieżdżone obiekty, tablice różnych kształtów, powiązane rekordy — JSON obsługuje to naturalnie. CSV nie może tego reprezentować bez utraty informacji lub tworzenia redundancji.
  • Zachowanie typów. W CSV wszystko jest ciągiem. true, 42, null i "true" wyglądają tak samo. Musisz wnioskować typy po stronie odbierającej, co prowadzi do błędów. JSON ma natywne wartości logiczne, liczby i null. inStock: true jest jednoznacznie wartością logiczną — bez zgadywania.
  • REST API i sieć. JSON to natywny format danych sieci. Każda biblioteka klienta HTTP, Fetch API każdej przeglądarki, każde REST i GraphQL API mówi JSON. Wysyłanie CSV przez HTTP jest możliwe, ale niezwykłe — potrzebujesz niestandardowego parsowania po obu stronach.
  • Bazy danych NoSQL. MongoDB, DynamoDB, Firestore, Elasticsearch, CouchDB — wszystkie używają JSON (lub binarnego nadzbioru jak BSON) jako natywnego formatu dokumentów. Zapisujesz JSON, dostajesz JSON.
  • Pliki konfiguracyjne. package.json, tsconfig.json, manifest.json — konfiguracja narzędzi standardowo używa JSON, ponieważ obsługuje zagnieżdżone struktury i jest łatwa do programowego generowania i walidacji.
  • Walidacja schematu. JSON Schema pozwala zdefiniować dokładny kształt dokumentu i walidować dane względem niego — sprawdzanie typów, wymagane pola, dopasowanie wzorców, ograniczenia tablic. CSV nie ma odpowiednika standardu.

Rozmiar pliku: prawdziwa historia

Twierdzenie "CSV jest mniejszy" jest prawdziwe w jednym konkretnym przypadku: duże płaskie tabele z wieloma wierszami. Weźmy 100 000 zdarzeń analitycznych, każde z ośmioma stałymi polami. W CSV nazwy pól pojawiają się raz w nagłówku. W JSON pojawiają się na każdym obiekcie. Ta powtarzalność sumuje się — tablica JSON może być o 30–50% większa niż równoważny CSV.

Ale odwróć scenariusz do zagnieżdżonych danych i matematyka się zmienia. Spłaszczony CSV naszego katalogu butów powtarza nazwę produktu, cenę i atrybuty w każdym wierszu wariantu. Wersja JSON przechowuje każdy produkt raz. Dla głęboko zagnieżdżonych danych z wieloma powtarzającymi się polami nadrzędnymi, JSON może być faktycznie mniejszy.

W praktyce, jeśli rozmiar pliku jest prawdziwym problemem, oba formaty doskonale kompresują się za pomocą gzip — powtarzające się nazwy kluczy w JSON i powtarzające się wartości wierszy w CSV oba mocno się kompresują. Serwowanie skompresowanego gzip JSON przez HTTP jest standardową praktyką, a różnica rozmiaru po kompresji zazwyczaj staje się pomijalna.

Porównanie narzędzi

Historia narzędzi dla każdego formatu odzwierciedla, gdzie jest najczęściej używany.

Narzędzia CSV: Excel, Google Sheets i LibreOffice Calc otwierają je natywnie. Biblioteka pandas sprawia, że CSV jest domyślnym dla analizy danych w Pythonie. Każda relacyjna baza danych ma polecenie importu/eksportu CSV. Narzędzia wiersza poleceń jak csvkit i xsv pozwalają filtrować, łączyć i agregować pliki CSV bez pisania kodu. Typ MIME to text/csv, zarejestrowany w IANA.

Narzędzia JSON: każdy język programowania ma wbudowany lub standardowo-biblioteczny parser JSON. JSON.parse() w JavaScript, json.loads() w Pythonie, encoding/json w Go, serde_json w Rust. Referencja MDN JSON jest jedną z najczęściej odwiedzanych stron MDN. W wierszu poleceń: jq jest niezbędny do zapytań i transformowania JSON. IDE automatycznie formatują i walidują go.

Jeśli pracujesz z pipeline'ami danych, które obejmują oba światy — ładowanie odpowiedzi API JSON do hurtowni danych lub eksportowanie rekordów bazy danych do arkusza kalkulacyjnego — będziesz regularnie konwertować między nimi. Konwerter CSV do JSON i JSON do CSV szybko to obsługują. Do porządkowania surowych plików przed przetwarzaniem, CSV Formatter i JSON Formatter warto dodać do zakładek.

Hybryda: JSON Lines (NDJSON)

Jest trzecia opcja warta poznania: JSON Lines, zwany też NDJSON (Newline-Delimited JSON). Pomysł jest prosty — jeden kompletny obiekt JSON na linię, bez otaczającej tablicy.

json
{"id":"SHOE-001","name":"Trail Runner Pro","price":129.99,"inStock":true,"variantCount":3}
{"id":"SHOE-002","name":"City Walker","price":89.99,"inStock":true,"variantCount":2}
{"id":"SHOE-003","name":"Summit Hiker","price":159.99,"inStock":false,"variantCount":5}

Ten format daje to, co najlepsze z obu światów dla określonych przypadków użycia. Jak CSV, możesz strumieniować i przetwarzać go linia po linii bez ładowania całego pliku do pamięci — kluczowe dla dużych plików dziennika lub wyjść pipeline'ów danych. Jak JSON, każda linia może mieć inny schemat i zachowuje typy. Możesz używać standardowych narzędzi Unix (grep, wc -l, head) do pracy z nim, ale też przesyłać każdą linię przez jq dla strukturalnych zapytań.

NDJSON jest szeroko używany do agregacji dzienników (to domyślny format wyjścia dla wielu ustrukturyzowanych loggerów), etapów pipeline'ów danych i eksportów danych treningowych ML. Jeśli piszesz skrypt, który przetwarza miliony rekordów i każdy rekord jest obiektem JSON, NDJSON jest zazwyczaj właściwym wyborem zamiast gigantycznej tablicy JSON — unikasz ładowania całości do pamięci i możesz łatwo wznowić od punktu kontrolnego.

python
import json

# Process a large NDJSON file without loading it all into memory
with open('products.ndjson', 'r') as f:
    for line in f:
        product = json.loads(line.strip())
        if product['inStock'] and product['price'] < 100:
            print(f"{product['name']} — ${product['price']}")

Przewodnik decyzyjny: CSV vs JSON

Oto praktyczna wersja. Gdy wybierasz między nimi, zadaj sobie te pytania:

  • Czy Twoje dane są naprawdę płaskie (bez zagnieżdżenia, bez tablic)? Jeśli tak, CSV jest prostszy. Jeśli nie, JSON.
  • Czy niebędący programistą będzie korzystał z tego pliku? Analitycy w Excelu? Użytkownicy biznesowi w Google Sheets? Użyj CSV.
  • Czy obsługujesz lub konsumujesz HTTP API? Użyj JSON. Bez dyskusji.
  • Czy robisz masowy import lub eksport bazy danych? Użyj CSV — każda baza danych obsługuje go natywnie.
  • Czy dane mają mieszane typy (wartości logiczne, liczby, nulle)? Użyj JSON, aby uniknąć błędów wnioskowania typów po stronie odbierającej.
  • Czy plik będzie przetwarzany wiersz po wierszu w strumieniowym pipeline'ie? Rozważ NDJSON jako punkt środkowy.
  • Czy przechowujesz konfigurację? Użyj JSON (lub YAML, jeśli komentarze są dla Ciebie ważne).
  • Czy schemat musi się różnić na rekord? JSON. CSV wymusza te same kolumny na każdym wierszu.
Uczciwe ustawienie domyślne: Jeśli budujesz coś dla innych programistów lub maszyn do konsumpcji, użyj JSON. Jeśli przekazujesz dane człowiekowi, który otworzy je w arkuszu kalkulacyjnym, użyj CSV. Jeśli budujesz pipeline danych przetwarzający miliony ustrukturyzowanych rekordów, rozważ NDJSON.

Podsumowanie

CSV i JSON nie konkurują naprawdę — rozwiązują różne problemy. CSV to właściwe narzędzie, gdy Twoje dane są tabelą i chcesz maksymalnej kompatybilności z narzędziami arkuszy kalkulacyjnych i baz danych. JSON to właściwe narzędzie, gdy Twoje dane mają strukturę, typy lub zagnieżdżenie, i gdy rozmawiasz z API lub aplikacjami.

Decyzja zazwyczaj nie jest trudna, gdy spojrzysz na rzeczywisty kształt danych. Płaskie wiersze odczytów czujników? CSV. Odpowiedź API z zagnieżdżonymi profilami użytkowników i osadzonymi historiami zamówień? JSON. Strumieniowy dziennik ustrukturyzowanych zdarzeń? NDJSON. Dopasuj format do kształtu danych i narzędzi po obu stronach, a rzadko się pomylisz.