Alasan kami menulis ini: kami adalah Geonode dan kami menjual proxy kepada orang-orang yang mengumpulkan data, sehingga kami sering melihat banyak dataset hasil scraping disimpan ke disk dalam format yang salah. Pernyataan penafiannya sederhana — pilihan format tidak ada hubungannya dengan proxy dan kami tidak mendapat keuntungan apa pun dari keputusan Anda dalam hal ini. Hal ini justru memengaruhi tagihan penyimpanan Anda, waktu pemrosesan Anda, dan berapa banyak waktu dalam seminggu yang Anda habiskan untuk menelusuri mengapa sebuah kolom yang berisi koma menyebabkan kegagalan impor di tahap selanjutnya. Itu adalah biaya nyata dan sepenuhnya berada dalam kendali Anda sebelum Anda menulis catatan pertama.
Perbedaan Mendasar: Yang Satu Adalah Standar, Yang Lain Adalah Kebiasaan
Inilah hal yang harus dipahami terlebih dahulu, karena segala hal lainnya berangkat dari sini.
JSON telah distandardisasi. RFC 8259 adalah dokumen Jalur Standar Internet. JSON memiliki tata bahasa formal, persyaratan wajib, dan secara eksplisit dibuat untuk menghilangkan “ketidakkonsistenan dengan spesifikasi JSON lainnya” serta memperbaiki “kesalahan spesifikasi”. Jika dua parser JSON tidak sepakat, setidaknya salah satunya salah dan spesifikasi tersebut akan menunjukkan mana yang salah.
CSV tidak demikian. RFC 4180 bersifat informasional, dan dokumen tersebut menyatakan hal itu dengan sangat jelas:
Meskipun terdapat berbagai spesifikasi dan implementasi untuk format CSV... tidak ada spesifikasi formal yang ada, sehingga memungkinkan adanya beragam interpretasi terhadap berkas CSV. Bagian ini mendokumentasikan format yang tampaknya diikuti oleh sebagian besar implementasi.
Ungkapan "tampaknya diikuti oleh sebagian besar implementasi" memiliki peran yang sangat besar dalam kalimat tersebut. RFC 4180 adalah deskripsi praktik umum, bukan definisi. Jika dua parser CSV tidak sepakat, keduanya mungkin benar.
Inilah sebabnya mengapa masalah CSV memiliki karakteristik seperti itu. Masalah tersebut bukanlah bug, melainkan ketidaksepakatan yang sah mengenai format yang tidak pernah didefinisikan sepenuhnya oleh siapa pun — yang juga menjadi alasan mengapa masalah tersebut muncul di batas-batas integrasi, berbulan-bulan setelah berkas tersebut dibuat, dalam perangkat lunak milik pihak lain.
Apa yang Sebenarnya Dijamin oleh CSV
RFC 4180 mendokumentasikan konvensi-konvensi umum, dan penting untuk mengetahui apa saja konvensi tersebut karena penyimpanganlah yang sering menjadi sumber masalah.
Setiap catatan dipisahkan oleh CRLF. Catatan terakhir mungkin memiliki atau tidak memiliki pemisah baris di bagian akhir. Mungkin terdapat baris header opsional. Bidang-bidang dipisahkan oleh koma, setiap baris harus memiliki jumlah bidang yang sama, dan "Spasi dianggap sebagai bagian dari bidang dan tidak boleh diabaikan."
Hal yang menarik adalah penggunaan tanda kutip:
Setiap bidang boleh atau tidak boleh diapit oleh tanda kutip ganda (namun beberapa program, seperti Microsoft Excel, sama sekali tidak menggunakan tanda kutip ganda).
Dan kolom "yang berisi baris baru (CRLF), tanda kutip ganda, dan koma harus diapit oleh tanda kutip ganda", dengan tanda kutip ganda yang tertanam di dalamnya "dihindari dengan mendahuluinya dengan tanda kutip ganda lainnya".
Perhatikan kata kerja modalnya. "Mungkin ada atau mungkin tidak." "Harus." RFC ini menjelaskan kecenderungan. Dan keterangan dalam tanda kurung mengenai Excel merupakan pengakuan dokumen tersebut, pada tahun 2005, bahwa alat CSV yang paling banyak digunakan di dunia tidak mengikuti konvensi tersebut.
Konsekuensi praktisnya, sesuai urutan dampaknya bagi Anda:
Pemisah bervariasi menurut wilayah. Negara-negara yang menggunakan koma sebagai pemisah desimal umumnya menggunakan titik koma sebagai pemisah kolom. File yang diekspor oleh rekan kerja di Jerman mungkin tidak dapat diparsing oleh pembaca berbasis koma, dan tidak ada di antara kalian yang melakukan kesalahan.
Enkoding tidak dinyatakan. Tidak ada informasi dalam berkas CSV yang menyatakan pengkodean karakternya. UTF-8, Latin-1, Windows-1252, dan UTF-16 semuanya menghasilkan berkas yang tampak seperti CSV namun terbaca sebagai karakter acak (mojibake) jika diproses oleh parser yang salah. Tanda urutan byte (byte order marks) muncul secara tidak konsisten dan mengganggu proses parsing header yang sederhana.
Akhir baris bervariasi. CRLF, LF, dan — pada kolom yang berisi baris baru tertanam — keduanya, di dalam tanda kutip.
Tipe data tidak ada. Semuanya adalah teks. 007 menjadi 7, 2026-09-02 menjadi tanggal di satu alat dan string di alat lain, serta + di awal baris menghilang. Proses bolak-balik CSV melalui spreadsheet benar-benar menyebabkan kehilangan data.
Dan berkas CSV dapat menjalankan kode. Bidang yang diawali dengan =, +, -, atau @ mungkin ditafsirkan sebagai rumus oleh perangkat lunak spreadsheet. Ini disebut injeksi rumus, yang merupakan kerentanan nyata ketika Anda menulis data yang disediakan pengguna ke dalam file CSV yang akan dibuka oleh seseorang di Excel, dan langkah mitigasi yang dapat dilakukan adalah dengan menambahkan tanda kutip tunggal di depan kolom tersebut atau menetralisirnya dengan cara lain sebelum menulisnya. Jika pipeline Anda menghasilkan file CSV dari konten yang diambil dari web atau dikirimkan oleh pengguna, hal ini perlu ditangani dengan hati-hati.
Apa yang Dijamin oleh JSON dan Di Mana Masih Ada Kendala
Spesifikasi JSON lebih ketat, dan jaminan yang diberikan pun lebih kuat.
Masalah pengkodean telah diselesaikan. RFC 8259 §8.1: "Teks JSON yang dipertukarkan antar sistem yang bukan bagian dari ekosistem tertutup HARUS dikodekan menggunakan UTF-8." Spesifikasi tersebut juga menyatakan bahwa implementasi "TIDAK BOLEH menambahkan tanda urutan byte" ke teks JSON yang dikirim melalui jaringan, sementara mengizinkan parser untuk mengabaikannya. Seluruh jenis masalah tebak-tebakan pengkodean yang sering terjadi pada CSV sama sekali tidak ada di sini.
Tipe data ada. String, bilangan, boolean, null, objek, dan array dapat dibedakan dalam tata bahasa. "007" dan 7 adalah nilai yang berbeda dan tetap berbeda.
Penumpukan (nesting) sudah menjadi bagian bawaan. Data hierarkis memiliki representasi yang jelas, bukan sekadar mengandalkan konvensi yang tidak disepakati bersama.
Dua hal di mana JSON tidak seabsolut yang diasumsikan orang:
Kunci yang duplikat hanya tidak disarankan. Spesifikasi menyatakan "Nama-nama dalam sebuah objek SEBAIKNYA unik" — SEBAIKNYA, bukan HARUS. Dan spesifikasi ini jujur mengenai konsekuensinya: ketika nama-nama tidak unik, "perilaku perangkat lunak yang menerima objek semacam itu tidak dapat diprediksi. Banyak implementasi hanya melaporkan pasangan nama/nilai terakhir. Implementasi lain melaporkan kesalahan atau gagal melakukan parsing."
Presisi bilangan hanyalah panduan, bukan aturan. Spesifikasi tersebut mengizinkan implementasi untuk menetapkan batasan pada rentang dan presisi, serta menyatakan bahwa interoperabilitas yang baik berasal dari tidak mengharapkan lebih dari yang disediakan oleh IEEE 754 binary64. Spesifikasi tersebut secara langsung menyebutkan kasus kegagalan: "Angka JSON seperti 1E400 atau 3.141592653589793238462643383279 dapat mengindikasikan potensi masalah interoperabilitas."
Dalam praktiknya, ini adalah bug tersembunyi yang sering terlewatkan. Identifier 64-bit yang besar kehilangan presisi saat diparsing menjadi bilangan JavaScript, tidak ada pengecualian yang dilemparkan, dan dua catatan yang berbeda dapat menjadi nilai yang sama. Mitigasi standar adalah menserialisasikan bilangan bulat besar sebagai string — yang sebaiknya dilakukan pada saat Anda menulis data, bukan setelah menemukannya di tahap selanjutnya. Kami telah membahas sisi parser dari masalah ini dalam panduan kami tentang JSON.parse.
Ukuran dan Kecepatan
Ada trade-off yang nyata, dan hasilnya tidak selalu sesuai dengan yang diharapkan orang.
CSV lebih kecil untuk data tabel datar, biasanya dengan selisih yang sangat besar, karena nama kolom hanya muncul sekali di header, bukan di setiap baris. Satu juta baris dengan lima kolom akan menyimpan lima nama kolom dalam CSV dan lima juta dalam JSON.
Kompresi memperkecil selisih tersebut secara drastis. Kunci yang berulang dapat dikompresi dengan sangat baik. Setelah gzip, penalti JSON pada baris yang seragam sering kali berkurang menjadi angka yang wajar — kadang-kadang bahkan menjadi nol. Jika Anda menyimpan data terkompresi, dan seharusnya memang demikian, argumen ukuran untuk CSV jauh lebih lemah daripada yang disarankan oleh angka mentah.
CSV diparsing lebih cepat untuk kasus sederhana dan lebih lambat untuk kasus yang benar. Parser naif split(',') sangat cepat namun salah. Parser yang sesuai standar yang menangani tanda kutip, baris baru tertanam, dan tanda kutip yang di-escape dengan benar memiliki biaya pemrosesan yang lebih mendekati JSON. Sebagian besar perbandingan kecepatan CSV secara diam-diam membandingkan parser yang salah dengan yang benar.
Biaya sebenarnya JSON adalah memori, bukan CPU. Sebuah dokumen JSON besar umumnya harus disimpan di memori untuk diparsing. CSV dapat diproses baris demi baris dari aliran data dengan penggunaan memori konstan. Untuk berkas berukuran sepuluh gigabyte, perbedaan tersebut bukan sekadar detail kinerja; melainkan perbedaan antara yang mungkin dan yang tidak mungkin pada mesin tertentu.
Dan itulah tepatnya masalah yang diselesaikan pada bagian berikutnya.
Solusi Tengah: JSON Lines
JSON Lines — juga dikenal sebagai NDJSON atau JSON yang dipisahkan oleh baris baru — adalah format di mana setiap baris mewakili satu dokumen JSON, tanpa array pembungkus. Ini adalah format yang seharusnya digunakan oleh kebanyakan orang, namun relatif sedikit yang mengetahuinya.
{"id": 1, "name": "Ada", "tags": ["engineer"]}
{"id": 2, "name": "Grace", "tags": ["engineer", "admiral"]}
Manfaatnya:
Streaming. Setiap baris diparsing secara independen, sehingga Anda dapat memproses berkas berukuran seratus gigabyte dengan penggunaan memori konstan. Hal ini menghilangkan kelemahan praktis terbesar JSON.
Penulisan hanya tambahkan (append-only). Catatan baru ditambahkan ke bagian akhir. Tidak ada array pembungkus yang perlu ditutup, yang berarti tidak perlu menulis ulang berkas dan tidak ada keluaran yang rusak jika proses terhenti di tengah penulisan.
Pemulihan parsial. File yang terpotong masih menghasilkan setiap baris yang lengkap. Array JSON yang terpotong tidak menghasilkan apa-apa sama sekali — satu tanda kurung yang hilang saja sudah membuat seluruh dokumen tidak dapat diparsing. Untuk apa pun yang ditulis oleh tugas yang berjalan lama, hal ini saja sudah cukup menjadi alasan untuk memilihnya.
Paralelisme yang sederhana. Dibagi per baris dan diproses secara independen. Tidak ada status lintas baris.
Semantik JSON lengkap. Tipe, penyarangan, dan pengkodean yang tidak ambigu, semuanya dipertahankan.
Biayanya wajar dan kecil: ukurannya sedikit lebih besar daripada CSV, tidak dapat dibuka langsung di spreadsheet, dan setiap catatan membawa kuncinya sendiri. Untuk data yang di-scrape, keluaran log, aliran peristiwa, dan apa pun yang ditambahkan secara bertahap, ini adalah pilihan default yang tepat — dan inilah yang akan kami sarankan kepada siapa pun yang menulis keluaran koleksi ke disk.
Melampaui Keduanya: Parquet dan Teman-temannya
Hal ini patut diketahui, karena untuk beban kerja analitis, perdebatan antara JSON versus CSV terkadang sama sekali bukan pertanyaan yang tepat.
Parquet bersifat kolom dan biner. Format ini menyimpan setiap kolom secara berurutan, yang berarti kueri yang melibatkan tiga kolom dengan masing-masing berisi empat puluh baris hanya akan membaca ketiga kolom tersebut. Format ini membawa skema, kompresinya jauh lebih baik daripada teks berorientasi baris karena nilai-nilai serupa disimpan berdekatan, dan mempertahankan tipe data dengan tepat.
Keunggulannya: kueri analitis pada kumpulan data besar, penyimpanan jangka panjang untuk data berukuran besar apa pun, dan pipa data apa pun yang mengalirkan data ke gudang data. Rasio kompresi dibandingkan CSV seringkali beberapa kali lipat, dan perbedaan kinerja kueri bahkan lebih besar lagi.
Kelemahannya: format ini tidak dapat dibaca manusia, tidak dapat ditambahkan data baru seperti halnya JSON Lines, dan memerlukan pustaka, bukan editor teks. Untuk streaming, pertukaran data dengan orang lain, dan data kecil, format teks tetap menjadi pilihan yang tepat.
Arsitektur yang umum dan masuk akal: kumpulkan data ke dalam JSON Lines karena format ini mudah ditambahkan dan toleran terhadap kehilangan data, kemudian konversikan ke Parquet secara bertahap untuk analisis dan pengarsipan. Gunakan setiap format di tempat yang sesuai dengan keunggulannya masing-masing.
Memilih Berdasarkan Tugas
| Tugas | Format | Alasan |
|---|---|---|
| Respons Web API | JSON | Sudah terintegrasi dengan alat HTTP, tipe data, dan struktur bersarang |
| Data yang dikumpulkan secara bertahap | JSON Lines | Dapat ditambahkan, dapat dialirkan, tetap utuh meski dipotong |
| Mengirim data ke rekan kerja non-teknis | CSV | Dapat dibuka di Excel, yang merupakan persyaratan sebenarnya |
| Konfigurasi | Tidak ada — YAML atau TOML | Komentar penting |
| Kumpulan data analitik besar | Parquet | Pembacaan kolom, kompresi, skema |
| Impor basis data massal | CSV | Pemuat jalur cepat bawaan di sebagian besar basis data |
| Aliran peristiwa atau log | JSON Lines | Satu peristiwa per baris, hanya dapat ditambahkan |
| Catatan bersarang atau berbentuk variabel | JSON atau JSON Lines | CSV tidak dapat mengekspresikannya tanpa membuat konvensi |
| Data dengan teks yang disediakan pengguna | JSON atau JSON Lines | Menghindari risiko kutipan, pembatas, dan injeksi rumus |
Tiga aturan yang menyelesaikan sebagian besar kasus tanpa perlu tabel.
Jika data bersifat datar, seragam, dan akan dimasukkan ke spreadsheet atau pemuat massal, gunakan CSV. Inilah keunggulan sejati CSV dan tidak ada format lain yang melakukannya dengan semudah ini. Impor massal ke database khususnya merupakan keunggulan nyata — sebagian besar mesin database memiliki jalur cepat untuk CSV, tetapi tidak untuk JSON.
Jika data bersarang, berbentuk variabel, atau berisi apa pun yang diketik pengguna, gunakan JSON atau JSON Lines. Meratakan data bersarang menjadi CSV memerlukan penciptaan konvensi, dan setiap konvensi yang diciptakan untuk tujuan ini selalu menjadi sumber bug. Sementara itu, teks pengguna mengandung koma, tanda kutip, dan baris baru, yang justru merupakan hal yang paling tidak dapat diandalkan oleh CSV.
Jika Anda menulis catatan secara berkelanjutan, gunakan JSON Lines. Bukan CSV, karena CSV tidak memiliki tipe data dan Anda akan kehilangannya. Bukan array JSON, karena tidak dapat ditambahkan secara aman dan proses yang crash akan meninggalkan file yang tidak dapat diparsing.
Pertanyaan Lainnya
Apakah JSON lebih baik daripada CSV?
Tergantung pada keperluannya, ya dan tidak. JSON adalah standar formal yang memiliki tipe data, struktur bersarang, dan pengkodean UTF-8 yang wajib. CSV lebih ringkas untuk data tabel datar, dapat dialirkan dengan mudah, dan dapat dibuka di aplikasi spreadsheet. Argumen yang lebih kuat adalah bahwa CSV tidak memiliki spesifikasi formal — RFC 4180 secara eksplisit menyatakan hal ini — yang membuatnya kurang dapat diprediksi di berbagai alat.
Mengapa file CSV saya rusak di Excel?
Biasanya karena pengkodean atau pemisah. File CSV tidak menyatakan pengkodean karakternya, sehingga Excel menebaknya, dan pengaturan wilayah yang menggunakan koma sebagai pemisah desimal mengharapkan pemisah titik koma. Kedua masalah ini melekat pada format yang tidak pernah menentukan keduanya. Mengekspor dalam UTF-8 dengan BOM sering kali membantu khusus untuk Excel, namun berisiko membingungkan parser lain.
Apa itu JSON Lines dan kapan saya harus menggunakannya?
Satu dokumen JSON per baris tanpa array pembungkus. Gunakan ini setiap kali Anda menulis catatan secara bertahap — data yang di-scrape, log, aliran peristiwa. Format ini mengalir dalam memori konstan, dapat ditambahkan dengan aman, tetap utuh meskipun dipotong (setiap baris lengkap tetap utuh), dan mempertahankan tipe JSON serta hierarki nesting secara penuh.
Apakah CSV lebih kecil daripada JSON?
Dalam bentuk tidak terkompresi dan untuk data datar yang seragam, biasanya jauh lebih kecil, karena nama kolom hanya muncul sekali, bukan per catatan. Setelah dikompresi, selisih ukurannya menyempit tajam, karena kunci yang berulang dapat dikompresi dengan sangat baik. Jika Anda menyimpan data terkompresi, argumen ukuran untuk CSV jauh lebih lemah daripada yang disarankan oleh angka mentah.
Apakah CSV dapat menangani data bersarang?
Tidak secara bawaan. Setiap penyarangan memerlukan konvensi yang Anda buat sendiri — meratakan data dengan nama kolom bertitik, string JSON di dalam sel, atau beberapa berkas terkait. Semua cara ini berfungsi, namun semuanya berarti CSV Anda tidak lagi dapat dibaca oleh alat umum tanpa konvensi khusus Anda, yang sebenarnya merupakan alasan utama penggunaan CSV sejak awal.
Mana yang lebih cepat diparsing, JSON atau CSV?
CSV, untuk kasus sederhana, tetapi perbandingan ini seringkali tidak adil — parser cepat seperti split(',') bukanlah parser CSV yang benar, dan parser yang menangani tanda kutip serta baris baru tertanam dengan benar memiliki biaya pemrosesan yang jauh lebih dekat dengan JSON. Perbedaan yang lebih penting adalah penggunaan memori: CSV diproses baris demi baris, sedangkan dokumen JSON umumnya perlu dimuat secara utuh, yang diperbaiki oleh JSON Lines.
Apakah kunci duplikat diperbolehkan dalam JSON?
Spesifikasinya menyatakan bahwa nama “SEBAIKNYA unik” alih-alih “HARUS”, jadi secara teknis hal itu diperbolehkan. Spesifikasi tersebut juga memperingatkan bahwa perilaku tidak dapat diprediksi jika kunci duplikat terjadi — beberapa parser akan mempertahankan yang terakhir, beberapa akan menampilkan kesalahan, dan beberapa akan gagal sepenuhnya. Perlakukan duplikat sebagai bug pada apa pun yang menghasilkan dokumen tersebut.
Format apa yang sebaiknya saya gunakan untuk data hasil scraping?
JSON Lines, dalam kebanyakan kasus. Rekaman hasil scraping sering kali bersarang dan bentuknya bervariasi, yang tidak ditangani dengan baik oleh CSV, dan pengumpulan datanya bersifat bertahap, yang tidak ditangani dengan baik oleh array JSON. Jika data benar-benar datar dan ditujukan untuk spreadsheet atau pemuatan massal, CSV sudah cukup — dan jika Anda menulis CSV dari teks yang di-scrape, netralkan bidang yang dimulai dengan =, +, -, atau @ untuk menghindari penyisipan rumus.
Kesimpulan
Kerangka pemikiran yang membuat keputusan ini menjadi mudah bukanlah "terstruktur versus sederhana". Melainkan, salah satu dari format ini memiliki spesifikasi, sedangkan yang lain hanya berisi deskripsi praktik umum. RFC 8259 menjelaskan apa yang harus dilakukan oleh JSON; RFC 4180 menjelaskan apa yang biasanya dilakukan oleh berkas CSV, dan mengatakannya dengan kata-katanya sendiri.
Perbedaan itulah yang pada dasarnya menjadi sumber setiap masalah CSV — pengkodean yang tidak dideklarasikan, pemisah yang bergantung pada pengaturan wilayah, penulisan tanda kutip yang tidak konsisten, tipe data yang hilang tanpa disadari saat diproses oleh spreadsheet, dan kolom yang berubah menjadi rumus. Tak satu pun dari hal ini merupakan bug pada parser siapa pun. Semua itu adalah hasil yang dapat diprediksi dari sebuah format yang tidak pernah didefinisikan sepenuhnya.
Bagi kebanyakan orang yang menulis data daripada membacanya, JSON Lines adalah solusinya, namun penggunaannya masih minim. Format ini mempertahankan tipe data, struktur bersarang, dan pengkodean yang telah ditetapkan dalam JSON, sekaligus menghilangkan satu-satunya kelemahan nyata JSON — format ini dapat dialirkan, ditambahkan dengan aman, dan tetap utuh meskipun penulisan terpotong, dengan setiap catatan lengkap tetap utuh. Gunakan CSV untuk dua tugas yang benar-benar paling dikuasainya: memberikan tabel datar kepada seseorang yang akan membukanya di spreadsheet, dan memuat data secara massal ke dalam basis data. Dan jika kumpulan data tersebut besar dan bersifat analitis, tidak ada satu pun format teks yang menjadi tujuan akhir yang tepat; konversikan ke format kolom dan biarkan setiap format melakukan tugas yang sesuai dengan fungsinya.
