連載Index(読む順・公開済(リンク)はここが最新): S00_門前の誓い_総合Index
テキストフォーマットを選ぶ時
「設定ファイルどうする?」「この一覧、Excelに渡せる?」「ファイル連携、相手は何が読める?」みたいに考えてはみるものの、そのとき判断してしまう基準は、結局これだ。
- 今まで扱ったことがある形式
- チームが慣れている形式
- 既存の資産がある形式
それ自体は自然。
ただ、そこで勢いで決めると、データの「形」だけじゃなく運用の「地雷」まで一緒に採用することになるのでよく検討しよう。
- CSV/TSV:区切り・改行・ダブルクォート・Excel。
- JSON:差分の読みづらさ・コメント不可・整形と順序の揺れ。
- YAML:インデント・型推論・実装差。
- INI:階層と配列の限界。
- XML:名前空間と冗長さ。
このページは、用途(初期値/設定/永続化/通信/表連携)と運用環境(誰が触るか)から、形式を選ぶための整理。
「互換性(バージョン/安全性)をどう作るか」はK30に記載。
1. ゴール
- CSV/TSV/JSON/XML/INI/YAMLを「用途(何のデータか)」と「運用環境(誰が触るか)」で選べるようになる
- 選定理由を言語化し、レビューでブレない基準に落とす
- 形式ごとの運用地雷(文字コード、改行、Excel、手編集、差分)を先に潰す
2. まず「用途」を言葉にする(ここが曖昧だと毎回揉める)
ここでいう用途は「表か構造か」より前の話。システムの中で何を扱うか。
- システムの初期値(デフォルト値、初回起動時のテンプレ)
- 設定ファイル(運用者が変える、環境で変わる、端末で変わる)
- 永続化(アプリ状態の保存、キャッシュ、オフライン用のローカル保存)
- データ通信(外部API、他システム連携、ファイル連携、バッチ受け渡し)
- 出力/受け渡し(Excelに渡す、監査/証跡として残す、ログに近い退避)
同じシステムでも用途は分かれる。ここを分けて考えると、選定が一気に楽になる。
2-1. 用途別の第一候補(最短の当て)
| 用途(システム内の役割) | ありがちな第一候補 | その理由 | 先に決めるべきこと |
|---|---|---|---|
| 初期値(テンプレ/デフォルト) | JSON / YAML | 構造を素直に持てる | 整形固定、コメント要否、差分の読みやすさ |
| 運用設定(人が手で触る) | INI(浅い) / YAML(構造) | 手編集・差分が強い | 記法制限、型推論回避、重複キー方針 |
| 永続化(アプリ状態/キャッシュ) | JSON | 実装が素直、取り回しが良い | 整形・分割・エラー時の切り分け |
| データ通信(内部/外部API) | JSON / XML(相手都合) | 現実的にJSONが多い。相手がXML前提なら合わせる | 契約(互換性)はK30、エラーの観測性 |
| ファイル連携(表データ) | CSV / TSV | 表として受け渡しやすい | 引用規約、Excel地雷、文字コード/改行 |
| Excelに渡す/部門連携 | CSV / TSV | 受け手がExcel中心 | Excel地雷(先頭0、日付化、指数表記) |
3. 「統一したい」も現実的。その時の考え方
同じシステムなら「1フォーマットに統一した方がやりやすい」という考え方は、実務では強い。
ただし統一の目的と例外の条件を決めないと、統一が負債になる。
3-1. 統一のメリット(現場で効く)
- 実装とライブラリが一本化される(読み書き、検証、ログ、例外処理)
- 教育コストが下がる(新メンバーが迷わない)
- 運用手順が揃う(配置場所、更新手順、差分レビュー)
3-2. 統一の落とし穴(よくある失敗)
- Excelに渡すのにJSON統一して、結局CSV変換が散らばる
- 表データまでJSON統一して、現場の目視/集計が辛くなる
- 設定を全部CSV/INIで統一して、階層や配列が来た瞬間に破綻する
- 外部連携まで統一しようとして、相手仕様に負ける(結局例外だらけ)
3-3. 実務での落としどころ(「基本 + 例外」を明文化)
- 基本フォーマットを1つ決める(例: JSON)
- 例外を用途で固定する(例: Excel連携はCSV、CI/CDはYAML、外部仕様がXMLならXML)
- 例外は担当者の好みで増やさない(増やすなら用途が増えた証拠として扱う)
例:
- 内部の永続化/設定: JSON
- Excelに渡す表データ: CSV/TSV
- CI/CD設定: YAML(ツール前提)
- 外部仕様がXML: XML(相手都合)
4. 運用環境の影響(用途とセットで見る)
用途が決まっても、運用環境で向き不向きが変わる。ここを無視すると「設計は正しいのに運用で死ぬ」。
| 運用環境(誰が触る/どこで使う) | 強くなる候補 | なぜ効くか | ありがちな事故 |
|---|---|---|---|
| Excelで開く/業務部門に渡す | CSV/TSV | 受け手がExcel中心 | 先頭0消失、日付化、指数表記、文字化け |
| Gitでレビューする(差分が命) | CSV(行が安定)/INI/YAML/整形JSON | 目視差分が運用コスト | JSON順序揺れ、minifyで差分死亡、CSV複数行レコードで崩壊 |
| 人が手で編集する | INI(浅い)/YAML(構造)/整形JSON | 手編集耐性が重要 | YAMLインデント事故、JSONにコメント入れて壊す |
| 外部仕様が決まっている | XML/CSV | 合わせるしかない | XML名前空間、CSV引用規約不一致 |
| CI/CDやIaCの設定 | YAML | 周辺ツールがYAML前提 | 型推論、インデント、実装差 |
5. 最短の決め方(用途→環境→形式)
5-1. 5問で決める
- 用途は何か(初期値/設定/永続化/通信/Excel受け渡し)
- Excelに渡す/表連携 -> CSV/TSV
- 外部仕様が固定 -> 相手仕様に合わせる(XML/CSVなど)
- それ以外 -> 2へ
- データは表か
- Yes -> CSV/TSV
- No -> 3へ
- 人が手で編集するか
- Yes(浅いKey-Value) -> INI
- Yes(階層/配列が必要) -> YAML/JSON
- No -> 4へ
- 周辺ツールの前提があるか(CI/CDがYAML等)
- Yes -> 前提に合わせる
- No -> 5へ
- 1フォーマット統一をやるか
- Yes -> JSONを基本にして例外を用途で固定
- No -> JSON/YAML/XMLを用途・環境で使い分け
5-2. 選定フロー図
6. フォーマットの最小例(形を先に掴む)
同じ内容を各形式にするとこうなる。
6-1. CSV(表)
Id,Name,Note
1,Alice,OK
2,Bob,"改行を含むメモ
カンマ,や""引用符""も混ざる"
6-2. TSV(表)
Id Name Note
1 Alice OK
2 Bob "改行を含むメモ
タブ や""引用符""も混ざる"
6-3. JSON(構造)
{
"id": 1,
"name": "Alice",
"note": "OK"
}
6-4. YAML(構造、手編集寄り)
id: 1
name: Alice
note: "OK"
6-5. XML(外部仕様で見ることが多い)
<Person>
<Id>1</Id>
<Name>Alice</Name>
<Note>OK</Note>
</Person>
6-6. INI(浅い設定)
[Person]
Id=1
Name=Alice
Note=OK
7. 形式別: 使いどころと運用地雷(用途の例つき)
ここで扱うのは「選定」と「運用地雷」。
互換性・バージョン・安全なデシリアライズ設計はK30に寄せる。
7-1. CSV(表の王道)
使いどころ(用途レベル)
- 表データの受け渡し(ファイル連携、バッチ)
- Excelに渡す一覧データ
- 監査用に「表として残す」退避
記述例(用途のイメージ)
- 表連携(エクスポート/インポート)
例: 取引一覧、エラー一覧、棚卸結果、集計結果、マスタ差分
ItemCode,Qty,Price,Note
00123,10,1200,"備考にカンマ,が混ざる"
00456,1,980,"改行が混ざると
1行=1レコードが崩れる"
運用地雷(具体)
- 引用規約(区切り/改行/ダブルクォート)を舐めると壊れる
Split(',')で読めるのは「たまたま壊れてないだけ」になりやすい。 - 改行を含むセルが来た瞬間、1行=1レコードが崩れる
レコードが複数行になり、差分レビュー、grep、行番号での切り分けが難しくなる。 - ダブルクォートのエスケープで見づらくなる
テキストが長い、カンマが多い、改行が多いほど"..."と""が増え、内容が追いにくい。 - Excelの勝手変換(先頭0、日付化、指数表記、桁落ち)
- 文字コード(BOMあり/なし)で文字化け
7-2. TSV(CSVのカンマ地雷を避ける)
使いどころ(用途レベル)
- 表連携だが、カンマが頻出する説明文を含む
- コピペや目視が多い表データ(ただしタブ混入が少ない前提)
記述例(用途のイメージ)
- 表連携(文章列が重い)
例: 問い合わせ内容、説明、ログ断片を含む一覧
Id Title Detail
1 障害 "カンマ,が多い文章でも列崩れしにくい"
2 調査 "タブ が混ざると列が崩れる"
運用地雷(具体)
- タブ混入で列が崩れる(見た目で気づきにくい)
- 改行を含むセルは結局引用が必要で、見づらさは残る
- Excel連携ならExcel地雷は避けられない
7-3. JSON(構造化は得意。運用は差分とコメントで詰む)
使いどころ(用途レベル)
- 初期値テンプレ(構造がある)
- 設定ファイル(ただし「人が手で触る」なら差分運用を先に決める)
- 永続化(アプリ状態/キャッシュ)
- データ通信(外部APIで多い)
記述例(用途のイメージ)
- 初期値テンプレ/設定ファイル(アプリ設定)
例: URL一覧、タイムアウト、機能フラグ、画面レイアウト
{
"features": { "isEnabled": true, "timeoutMs": 3000 },
"endpoints": [
{ "name": "primary", "url": "https://api.example.com" }
]
}
- 永続化(キャッシュ/状態保存)
例: 最終ログイン、最近使ったファイル、検索履歴
{ "lastLoginUtc": "2026-01-18T06:00:00Z", "recentFiles": ["a.txt","b.txt"] }
運用地雷(具体)
- コメントが書けない
設定に「なぜこの値か」を書きたくなるが、JSONは仕様上コメントが無い。
その結果、//や/* */を入れて壊す、別の場所にメモが散って迷子になる、が起きる。 - 整形が揺れると差分が読めない
minify(1行)にすると、パースエラーが「列 15342」になり切り分け不能になる。
整形しても、出力ツールが変わるとインデント/改行が揺れて差分がノイズになる。 - 順序が揺れるとレビューが止まる
JSONのプロパティ順は本質ではないが、Git差分では順序が重要になる。
自動整形やシリアライザが順序を変えると、実質変更が埋もれる。 - 階層が深い/巨大ファイルだと追いにくい
波括弧と角括弧が続き、エラー位置がどのブロックか追いにくい。
配列の中に同型オブジェクトが続くと、どの要素が壊れているかも目視で追いづらい。 - マージコンフリクトが起きやすい
1つの大きいJSONを複数人で触ると、同じ行付近で衝突しやすい。
7-4. YAML(手編集に強いが、インデントと型推論が敵)
使いどころ(用途レベル)
- CI/CDなどツール設定(前提としてYAMLが多い)
- 運用設定で「コメントが必要」「手編集が中心」
記述例(用途のイメージ)
- CI/CDやデプロイ設定
例: ジョブ、環境変数、実行条件、手順
jobs:
build:
steps:
- run: dotnet test
# 理由や注意点をコメントで残せる
- 運用設定(人が手で編集する構造)
例: 環境ごとのエンドポイント、機能の有効化
features:
isEnabled: true
endpoints:
- name: primary
url: https://api.example.com
運用地雷(具体)
- インデントが意味を持つ(見た目のズレが意味のズレ)
- 型推論で意図しない型になる(yes/no、001、日付っぽい値など)
- 実装差で挙動が割れる(同じYAMLでもツールにより解釈差が出る)
7-5. XML(外部仕様が強い連携に寄せる)
使いどころ(用途レベル)
- 外部仕様でXML指定
- 既存資産やスキーマ(XSD)前提の連携
- 厳密な検証が必要で、周辺ツールもXML前提
記述例(用途のイメージ)
- 外部連携(相手仕様がXML)
例: 既存の基幹、業界標準、スキーマ付きファイル連携
<Request xmlns="urn:example:v1">
<Header>
<RequestId>abc-123</RequestId>
</Header>
<Body>
<Amount>1200</Amount>
</Body>
</Request>
運用地雷(具体)
- 名前空間で転ぶ(同じ要素名でも別扱いになり、合わないと読めない)
- 冗長で手編集が辛い(差分もノイズが増えやすい)
- 整形方針が揺れると差分がノイズになる
7-6. INI(端末別の小さい上書きだけに使う)
使いどころ(用途レベル)
- 端末ローカルの設定(WinFormsの個人差分など)
- 小さい運用設定(画面分程度)を手で直す
記述例(用途のイメージ)
- 端末別の上書き(軽い設定)
例: 画面サイズ、ログレベル、接続先の切替(ローカルだけ)
[App]
Theme=Dark
LogLevel=Info
TimeoutMs=3000
[Window]
Width=1280
Height=720
運用地雷(分かりやすく言うと)
- 「階層」や「配列」が来た瞬間に終わる
INIは基本的に「キー=値」。構造を持たせると無理やりになって破綻する。 - 重複キーの解釈が揺れる
Key=...が2回出たときに「後勝ち/先勝ち/エラー」が実装で変わる。
8. 地雷マップ
8-0. 全体像
8-1. TOOL: Excel/周辺ツール起因
8-2. PARSE: パース/構文起因
8-3. DIFF: 差分/レビュー起因
8-4. EDIT: 手編集/運用起因
8-5. INTEROP: 外部連携/相手仕様起因
9. 形式より先に固定すべき運用仕様
形式を決めても、運用仕様が決まっていないと不具合になる。最低限ここは決める。
- 文字コード: UTF-8固定が基本(BOMの有無も決める)
- 改行: LF/CRLFを固定(Excelや社内ツール都合があるなら先に決める)
- 更新方式: 原子的更新(テンポラリ -> 置換)を標準にする
- 入力検証: 壊れたデータを握り潰さず、どこで壊れたかを出す
- 失敗時のログ: ファイルパス、行番号(またはキー名/JSONパス)、例外を残す
- サンプル: 正常サンプルをリポジトリに置く(実運用の基準になる)
10. 実装の最小セット(選定後の最低ライン)
10-1. 原子的更新(テンポラリを書いてから差し替える)
using System.Text;
public static class AtomicFile
{
public static void WriteAllTextAtomic(string path, string content, Encoding encoding)
{
var dir = Path.GetDirectoryName(path) ?? ".";
Directory.CreateDirectory(dir);
var tmp = path + ".tmp";
File.WriteAllText(tmp, content, encoding);
if (File.Exists(path))
{
var bak = path + ".bak";
File.Replace(tmp, path, bak, ignoreMetadataErrors: true);
}
else
{
File.Move(tmp, path);
}
}
}
10-2. JSON(.NET 8) 整形を固定する
using System.Text.Json;
public static class JsonText
{
private static readonly JsonSerializerOptions Options = new()
{
WriteIndented = true,
PropertyNameCaseInsensitive = true
};
public static string Serialize<T>(T value) => JsonSerializer.Serialize(value, Options);
public static T? Deserialize<T>(string json) => JsonSerializer.Deserialize<T>(json, Options);
}
10-3. CSV/TSVは手実装しない(方針にする)
CSV/TSVは引用規約が本体。Split(',') や Split('\t') は「壊れたら終わる」実装になりやすい。
方針として「実装はライブラリに任せる」を決めると事故が減る。
- 例:
CsvHelperなど(区切り文字を変えればCSV/TSV両対応がしやすい)
10-4. YAMLは記法と型推論を縛る
- 高度機能(アンカー、マージ)は原則禁止
- 型推論で不具合になる値はクォートする(yes/no、001、日付っぽい値など)
- 整形(インデント幅)を統一する
11. チートシート(用途で引く)
- 初期値テンプレ: JSON / YAML(コメントが要るならYAML、差分運用できるなら整形JSON)
- 設定ファイル(運用者が触る): INI(浅い) / YAML(構造) / 整形JSON(差分運用を決めた場合)
- 永続化(アプリ状態/キャッシュ): JSON
- データ通信(外部API): JSON(相手都合でXMLもあり)
- ファイル連携(表データ): CSV/TSV
- Excelに渡す: CSV/TSV(Excel地雷を仕様に入れる)
- 形式統一をやる: JSONを基本にして、例外を用途で固定する
関連トピック
- シリーズ総合Index(読む順・公開済リンクが最新)
- K30 【鍛錬】シリアライズ設計 互換性 バージョン セキュリティの落とし穴