この記事を書いた理由:私たちはGeonodeという企業で、データ収集を行う方々にプロキシを販売しています。そのため、スクレイピングされたデータセットが誤った形式でディスクに書き込まれるケースを数多く目にしてきました。免責事項は簡単です――形式の選択はプロキシとは一切関係がなく、この選択によって当社が利益を得ることもありません。 影響を受けるのは、ストレージ料金、処理時間、そしてコンマを含むフィールドが原因で下流のインポートが失敗した理由をデバッグするために1週間のうちどれだけの時間を費やすか、といった点です。これらは現実的なコストであり、最初のレコードを書き込む前に、すべてご自身でコントロールできる範囲内にあるのです。
根本的な違い:一方は標準、もう一方は慣習
まず理解すべきはこれです。なぜなら、他のすべてはこの点から派生するからです。
JSONは標準化されています。 RFC 8259 は、インターネット標準トラック文書です。 JSONには正式な文法と必須要件があり、「他のJSON仕様との不整合」を解消し、「仕様の誤り」を修正するために明示的に存在しています。2つのJSONパーサーの解釈が一致しない場合、少なくとも一方は間違っており、仕様書によってどちらが間違っているかが明示されています。
CSVはそうではありません。 RFC 4180は情報文書(Informational)であり、そのことを極めて平易な言葉で次のように述べています:
CSV形式には様々な仕様や実装が存在しますが……正式な仕様は存在しないため、CSVファイルの解釈には幅広いばらつきが生じます。 本節では、ほとんどの実装で採用されていると思われる形式について記述する。
「ほとんどの実装で採用されていると思われる」という表現は、この文において非常に重要な役割を果たしている。RFC 4180は一般的な慣行の記述であり、定義ではない。2つのCSVパーサーの結果が一致しない場合、どちらも正しい可能性がある。
これが、CSVの問題が特有の性質を持つ理由です。これらはバグというよりは、誰も完全に定義したことのないフォーマットに関する正当な意見の相違であり、だからこそ、ファイルが作成されてから数ヶ月後、他の誰かのツール上で、システム間の連携部分において問題が表面化するのです。
CSVが実際に保証していること
RFC 4180には一般的な規約が記載されています。規約からの逸脱が問題の原因となるため、その内容を把握しておく価値があります。
レコードはCRLFで区切られます。最後のレコードの末尾に改行がある場合もあれば、ない場合もあります。オプションでヘッダー行が存在する場合もあります。フィールドはコンマで区切られ、各行のフィールド数は同じである必要があります。また、「スペースはフィールドの一部とみなされ、無視してはならない」とされています。
引用符の扱いが興味深い点です:
各フィールドは二重引用符で囲むことも、囲まないことも可能です(ただし、Microsoft Excel などの一部のプログラムでは、二重引用符を一切使用しません)。
また、「改行(CRLF)、二重引用符、およびコンマを含むフィールドは二重引用符で囲むべき」であり、フィールド内に二重引用符が含まれる場合は、「その前に別の二重引用符を付けることでエスケープする」必要があります。
「~する場合もあれば、そうでない場合もある」「~すべき」といった条件を表す動詞に注目してください。 このRFCは傾向を記述しているに過ぎない。また、Excelに関する括弧内の記述は、2005年時点で、世界で最も広く使用されているCSVツールがこの規約に従っていないことを、この文書が認めていることを示している。
実用上の影響は、問題が発生する順に以下の通りである:
区切り文字はロケールによって異なります。 小数点区切りとしてコンマを使用する国では、フィールド区切りとしてセミコロンを使用するのが一般的です。ドイツの同僚がエクスポートしたファイルは、コンマベースのリーダーでは解析できない可能性がありますが、どちらにも非はありません。
エンコーディングは宣言されていません。 CSVファイルには、その文字エンコーディングを示す記述が一切ありません。UTF-8、Latin-1、Windows-1252、UTF-16のいずれも、CSVのように見えるファイルを生成しますが、不適切なパーサーでは文字化けとして読み込まれます。バイトオーダーマーク(BOM)は不規則に現れ、単純なヘッダー解析を妨げます。
改行コードは様々です。 CRLF、LF、そして — 改行が埋め込まれたフィールド内では — 引用符内の改行も同様です。
データ型は存在しません。 すべてがテキストです。007は7となり、2026-09-02はあるツールでは日付として扱われ、別のツールでは文字列として扱われ、先頭の+は消えてしまいます。 スプレッドシートを介してCSVを往復処理すると、実際にデータが失われます。
さらに、CSVファイルはコードを実行する可能性があります。 =、+、-、または@で始まるフィールドは、スプレッドシートソフトウェアによって数式として解釈される可能性があります。 これは「数式インジェクション」と呼ばれ、ユーザーが提供したデータをCSVに書き込み、誰かがそれをExcelで開く場合、深刻な脆弱性となります。対策としては、書き込み前にそのようなフィールドの先頭に単一引用符を付けるか、その他の方法で無効化することが挙げられます。スクレイピングやユーザーからの投稿コンテンツからCSVを生成するパイプラインを使用している場合は、この問題に意図的に対処する価値があります。
JSONが保証することと、依然として問題となる点
JSONの仕様はより厳格であり、それに応じて保証もより強固です。
エンコーディングは明確に定められている。 RFC 8259 §8.1:「閉じたエコシステムの一部ではないシステム間で交換されるJSONテキストは、UTF-8を使用してエンコードされなければならない(MUST)。」 また、実装はネットワーク上のJSONテキストに「バイト順マークを追加してはならない」と規定されている一方で、パーサーがそれを無視することは許容されている。CSVを悩ませているエンコーディングの推測に関する問題の類は、ここではそもそも存在しない。
型が存在する。 文字列、数値、ブール値、null、オブジェクト、配列は、文法上区別可能である。"007" と 7 は異なる値であり、その違いは維持される。
ネストはネイティブにサポートされている。 階層的なデータには、誰も合意していない慣習を必要とせず、明確な表現形式が存在する。
JSONが人々が想定しているほど絶対的ではない点が2つあります:
キーの重複は単に推奨されないだけです。 仕様書には「オブジェクト内の名前は一意であるべきである(SHOULD)」とあります。これは「MUST」ではなく「SHOULD」です。また、その結果についても率直に述べています。名前が一意でない場合、「そのようなオブジェクトを受け取るソフトウェアの挙動は予測不能である。 多くの実装では、最後の名前と値のペアのみを報告します。他の実装ではエラーを報告したり、解析に失敗したりします。」
数値の精度は指針であり、規則ではありません。 仕様書では、実装が範囲や精度に制限を設けることを認めており、IEEE 754 binary64が提供する範囲を超えることを期待しないことが、良好な相互運用性につながるとしています。 また、失敗ケースについても直接言及しています。「1E400 や 3.141592653589793238462643383279 のような JSON 数値は、相互運用性の問題を引き起こす可能性があることを示しているかもしれない。」
実際には、これは出荷時に見過ごされがちな「サイレントバグ」です。大きな64ビットの識別子は、JavaScriptの数値として解析される際に精度が失われますが、例外は発生せず、本来異なる2つのレコードが同じ値になってしまう可能性があります。標準的な回避策は、大きな整数を文字列としてシリアライズすることです。これは、下流で問題が発覚するのを待つよりも、データを書き込む段階で実施しておく価値があります。 この問題のパーサー側については、JSON.parseに関するガイドで詳しく解説しています。
サイズと速度
このトレードオフは確かに存在し、その傾向は必ずしも人々の予想通りとは限りません。
フラットな表形式のデータの場合、CSVの方がファイルサイズが小さい。これは通常、フィールド名が各レコードごとに記述されるのではなく、ヘッダーに一度だけ記述されるため、その差は圧倒的です。5つのフィールドからなる100万行のデータの場合、CSVでは5つのフィールド名が保存されるのに対し、JSONでは500万個のフィールド名が保存されます。
圧縮を行うと、その差は劇的に縮まります。 繰り返し出現するキーは極めて効率的に圧縮されます。 gzipで圧縮すると、均一なレコードに対するJSONのパフォーマンス低下は、多くの場合、ごくわずかなものになり、時にはゼロになることもあります。圧縮データを保存している場合(そうすべきですが)、CSVのサイズに関する議論は、生の数値が示唆するよりもはるかに説得力が弱くなります。
単純なケースではCSVのパースが速いですが、正しい形式のデータでは遅くなります。 単純なsplit(',')は非常に高速ですが、誤った処理になります。引用符、埋め込み改行、エスケープされた引用符を正しく処理する規格準拠のパーサーの場合、その処理コストはJSONの解析に近くなります。CSVの速度比較の多くは、知らず知らずのうちに誤ったパーサーと正しいパーサーを比較しているに過ぎません。
JSONの真のコストはCPUではなくメモリです。 通常、1つの大きなJSONドキュメントを解析するには、それをメモリに保持する必要があります。一方、CSVはストリームから行単位で処理できるため、メモリ使用量は一定に抑えられます。10ギガバイトのファイルの場合、この違いは単なるパフォーマンス上の細部ではなく、特定のマシンにおいて「可能」か「不可能」かを分ける決定的な要因となります。
そして、まさにこの問題を次のセクションで解決します。
中間の選択肢:JSON Lines
JSON Lines(NDJSON や改行区切り JSON とも呼ばれる)は、1 行に 1 つの JSON ドキュメントが記述され、囲みとなる配列がない形式です。これは、ほとんどの人が採用すべき形式であるにもかかわらず、その存在を知っている人は比較的少ないものです。
{"id": 1, "name": "Ada", "tags": ["engineer"]}
{"id": 2, "name": "Grace", "tags": ["engineer", "admiral"]}
これにより得られる利点:
ストリーミング処理。 各行が独立して解析されるため、100ギガバイトのファイルでも定数メモリで処理できます。これにより、JSONが抱える最大の実用上の欠点が解消されます。
追記専用書き込み。 新しいレコードは末尾に追加されます。囲む配列を閉じる必要がないため、ファイルの書き換えが不要であり、書き込み途中でプロセスが異常終了しても出力が破損することはありません。
部分的な復旧。 ファイルが切り詰められていても、完全な行はすべて取得できます。一方、切り詰められたJSON配列からは何も得られません。括弧が1つ欠けるだけで、ドキュメント全体が解析不能になってしまいます。長時間実行されるジョブによって書き込まれたデータについては、この点だけでもこの選択が正当化されます。
容易な並列処理。 行ごとに分割し、各シャードを独立して処理します。行をまたぐ状態管理は不要です。
完全なJSONセマンティクス。 型、ネスト、曖昧さのないエンコーディングがすべて保持されます。
コストは明確かつ小さい:CSVよりわずかに大きくなり、スプレッドシートで直接開くことはできず、各レコードにはキーが含まれる。スクレイピングされたデータ、ログ出力、イベントストリーム、および増分的に追加されるあらゆるものにとって、これは適切なデフォルト設定であり、ディスクにコレクション出力を書き込むすべての人に推奨するものである。
両者を超えた存在:Parquetとその仲間たち
知っておく価値があります。なぜなら、分析ワークロードにおいては、「JSONかCSVか」という問い自体が、場合によっては全く的外れな問いになることがあるからです。
Parquetは列指向かつバイナリ形式です。各列を連続して格納するため、40の値を持つ3つの列にアクセスするクエリでは、その3つの列のみが読み込まれます。 スキーマを持ち、類似した値が隣接して配置されるため行指向のテキスト形式よりもはるかに高い圧縮率を実現し、型情報を正確に保持します。
優れている点:大規模なデータセットに対する分析クエリ、大容量データの長期保存、およびデータウェアハウスにデータを供給するあらゆるパイプライン。CSVと比較した圧縮率はしばしば数倍に達し、クエリパフォーマンスの差はさらに大きくなります。
劣る点:人間が直接読み取ることができず、JSON Linesのように追記できず、テキストエディタではなくライブラリが必要となる。ストリーミング処理、人とのデータ交換、および小規模なデータについては、テキスト形式が依然として適している。
一般的かつ合理的なアーキテクチャ:追加が容易でデータ損失に耐性があるJSON Lines形式でデータを収集し、分析やアーカイブのためにバッチ処理でParquet形式に変換する。それぞれの形式が持つ特長を活かして活用する。
用途に応じた選択
| 用途 | 形式 | 理由 |
|---|---|---|
| Web APIのレスポンス | JSON | HTTPツールや型、ネスト構造にネイティブに対応 |
| 段階的に書き込まれるスクレイピングデータ | JSON Lines | 追記可能、ストリーム処理可能、切り捨て時にもデータが保持される |
| 技術に詳しくない同僚へのデータ送信 | CSV | Excelで開ける(これが実際の要件) |
| 設定 | どちらでもない — YAML または TOML | コメントが重要 |
| 大規模な分析用データセット | Parquet | 列指向の読み取り、圧縮、スキーマ |
| データベースへの一括インポート | CSV | ほとんどのデータベースにネイティブな高速ロード機能がある |
| イベントまたはログストリーム | JSON Lines | 1行につき1イベント、追記専用 |
| ネストされたレコードや可変形状のレコード | JSON または JSON Lines | CSVでは、独自の規約を考案しない限り表現できない |
| ユーザーが指定した任意のテキストを含むデータ | JSON または JSON Lines | 引用符、区切り文字、および数式注入のリスクを回避 |
テーブルを必要とせずにほとんどのケースを解決する3つのルール。
データがフラットで均一であり、スプレッドシートや一括インポートツールに読み込む場合は、CSVを使用してください。 これらはまさにCSVの強みであり、これほど便利に実現できる形式は他にありません。特にデータベースへの一括インポートは大きな利点です。ほとんどのエンジンでは、JSONではなくCSVに対して高速な処理パスが用意されています。
データがネストされていたり、形状が可変であったり、ユーザーが入力した内容が含まれている場合は、JSONまたはJSON Linesを使用してください。 ネストされたデータをCSVに平坦化するには、独自の規約を考案する必要がありますが、これまでに考案されたあらゆる規約がバグの原因となってきました。一方、ユーザーが入力したテキストにはコンマ、引用符、改行が含まれており、これらはまさにCSVが最も信頼性に欠ける処理対象です。
レコードを連続して書き込む場合は、JSON Linesを使用してください。 CSVは型情報を持ちませんので、型情報が失われてしまうため使用しないでください。JSON配列も、安全に追加することができず、プロセスがクラッシュすると解析不能なファイルが残ってしまうため、使用しないでください。
よくある質問
JSONはCSVより優れていますか?
用途によって、イエスともノーとも言えます。JSONは、型、ネスト、およびUTF-8エンコーディングが必須とされる正式な標準規格です。一方、CSVはフラットな表形式のデータではファイルサイズが小さく、ストリーム処理に適しており、スプレッドシートで直接開くことができます。 より決定的な指摘としては、CSVには正式な仕様が存在しないという点があります(RFC 4180でも明示的に述べられています)。そのため、ツール間で予測可能な挙動が得られにくいのです。
なぜExcelでCSVファイルが正しく表示されないのですか?
通常はエンコーディングか区切り文字が原因です。 CSVファイルは文字エンコーディングを宣言しないため、Excelが推測します。また、小数点区切りとしてコンマを使用するロケールでは、区切り文字としてセミコロンが期待されます。これらの問題は、どちらも仕様で定義されていないこのフォーマットに固有のものです。特にExcelの場合、BOM付きのUTF-8でエクスポートすると改善されることがよくありますが、その代償として他のパーサーを混乱させることになります。
JSON Linesとは何ですか?いつ使用すべきですか?
1行につき1つのJSONドキュメントで、配列のネストはありません。レコードを段階的に書き込む場合(スクレイピングデータ、ログ、イベントストリームなど)には、いつでも使用してください。メモリ上でストリーム処理が可能で、安全に追加でき、切り捨てされても完全な行はそのまま保持され、完全なJSON型とネスト構造を維持します。
CSVはJSONよりもファイルサイズが小さいですか?
非圧縮で、フラットかつ均一なデータの場合、通常は大幅に小さくなります。これは、フィールド名がレコードごとにではなく一度だけ出現するためです。圧縮後は、繰り返されるキーが非常に効率的に圧縮されるため、その差は急激に縮まります。圧縮データを保存する場合、CSVのサイズ面での優位性は、生の数値が示唆するほど強くはありません。
CSVはネストされたデータを扱えますか?
ネイティブには扱えません。ネストを扱うには、ドット区切りの列名による平坦化、セル内のJSON文字列、あるいは複数の関連ファイルといった、独自に考案した規約が必要です。 これらはいずれも機能しますが、いずれも、独自の規約がない限り汎用ツールではCSVを読み取れなくなってしまいます。そもそもCSVを使用する主な理由のほとんどは、汎用ツールでの読み取り可能性にあるのです。
JSONとCSV、どちらの解析が速いですか?
単純なケースではCSVですが、この比較はしばしば不公平です。高速なsplit(',')は正しいCSVパーサーとは言えず、引用符や埋め込み改行を適切に処理するパーサーの場合、処理コストはJSONにかなり近づきます。より重要な違いはメモリ使用量です。CSVは行ごとにストリーム処理されるのに対し、JSONドキュメントは通常、全体を読み込む必要がありますが、これはJSON Linesによって解決されます。
JSONでは重複するキーは許可されていますか?
仕様書では、名前は「MUST」ではなく「SHOULD be unique」とされているため、技術的には許可されています。また、重複がある場合の挙動は予測不能であるとも警告されています。パーサーによっては最後の値を採用するものもあれば、エラーを返すもの、完全に処理に失敗するものもあります。重複は、そのドキュメントを生成した側におけるバグとして扱うべきです。
スクレイピングしたデータにはどの形式を使うべきか?
ほとんどの場合、JSON Lines です。スクレイピングされたレコードはネストされていたり、構造が一定でなかったりすることが多く、CSV ではこれをうまく処理できません。また、データの収集は増分で行われることが多く、JSON 配列ではこれをうまく処理できません。 データが真にフラットで、スプレッドシートや一括読み込みを目的としている場合は、CSVでも問題ありません。また、スクレイピングしたテキストからCSVを作成する場合は、数式の挿入を防ぐために、=、+、-、または@で始まるフィールドを無効化してください。
まとめ
この決定を容易にする視点は、「構造化されているか、単純であるか」という対比ではありません。重要なのは、一方の形式には仕様があり、もう一方には一般的な慣行の説明があるという点です。 RFC 8259はJSONが何をしなければならないかを規定しています。一方、RFC 4180はCSVファイルが通常どのように振る舞うかを示しており、そのことを独自の言葉で説明しています。
この違いこそが、実質的にすべてのCSV問題の根源です。宣言されていないエンコーディング、ロケールに依存する区切り文字、一貫性のない引用符の扱い、スプレッドシート処理で黙って失われる型、そして数式に変換されてしまうフィールドなどです。これらはいずれも、どのパーサーのバグでもありません。これらは、完全に定義されなかったフォーマットから生じる、予測可能な結果なのです。
データを読み取るのではなく書き込む大多数の人にとって、JSON Linesこそが解決策であり、その採用率は低いのが現状です。JSON Linesは、JSONの型、ネスト構造、確立されたエンコーディングを維持しつつ、JSONの唯一の真の弱点を排除しています。つまり、ストリーム処理が可能で、安全に追加書き込みができ、書き込みが途中で切り詰められても、完全なレコードはすべて無傷のまま残ります。 CSVは、それが真に最も得意とする2つの用途――スプレッドシートで開く相手にフラットな表を渡すこと、およびデータベースへの一括読み込み――に限定して使いましょう。また、データセットが大規模で分析を目的とする場合、どちらのテキスト形式も適切な最終的な保存形式とは言えません。カラム形式に変換し、それぞれの形式がその目的に合わせて設計された役割を果たせるようにしましょう。
