CSV(Comma-Separated Values)はよくあるファイル形式で、主にデータを受け渡しする際に利用されます。
とてもよく利用されてはいますが、「標準」というものがありません。
各ベンダやシステムごとに扱いが異なる場合があるのが現状です。
相手先システムの仕様がわかっている場合は、初期段階で確認して要件に含めます。
特に拠り所となる仕様がない場合でも、設計書には下記のような視点で決定し、すべて記載しましょう。
読み込み側システムを作る際には、設計書に記載があれば問題の多くを回避できます。
1. ファイル形式
ファイルの形式が出力と入力で異なると問題が発生しますが、簡易なテキストエディタ (Windowsのメモ帳など) では確認が難しいことがあります。
トラブルの防止のためにもきちんと決めておくことが重要です。
- 文字コード (例: UTF-8, Shift-JIS, ISO-8859-1)
- 近年はUTF-8が一般的になっているようですが、利用する環境に合わせて考慮が必要になります。
- BOM (Big, Little, なし)
- 文字コードによってはBOM (Byte Order Mark) も決める必要があります。
- UTF-8ではエンディアンの扱いはありませんが、Unicodeかどうかの自動判別のために必要な場合があるため確認が必要です。
- 有り無しの違いで問題が起こる環境/システムもありますので、相手側システムの仕様を確認して決定します。
- EOF (あり, なし)
- ファイルの終了コード EOF (End of File) の有無も任意の様です。
- 決めの問題ですが、決めたら仕様として記載します。
- 相手システムが先に決まっているのであればそれに合わせます。
2. レコード構造
データ1件ごとのルールです。
あまりブレの少ない部分で、多くの場合同じような仕様ですが、異なるシステムもありますので決めておく必要があります。
- 区切り文字 (カンマ
,
、セミコロン;
、タブ\t
など)- CSVといった場合、多くの場合はカンマです。
- Character Separated Values と呼ばれるCSVも存在しており、設計では区切り文字が何であるかは明示するべきです。
- 各レコードの構造 (フィールド数が一定か、可変か)
- 一般的には、CSVのフィールド数は一定とする事が多いです。
- フィールド数が一定の場合は値のない部分は区切り文字 (カンマ)が並ぶことになります。
- フィールド数が可変のCSVファイルも存在しますが、読込側で考慮する必要があり好まれません。
- フィールド囲み文字 (ダブルクォート
"
、シングルクォート'
)- フィールドの囲み文字は、多くはダブルクォートです。
- 必要が無い場合に囲み文字を置かない場合が多いようですが、すべての項目を囲むケースもあります。
- レコード終了の定義 (例: LF
\n
、CR\r
、CRLF\r\n
、閉じられていない引用符)- 一般にCSVはレコードの区切りに改行を利用します。
- そのシステムで利用される改行コードは処理系により異なりますが、CSVの出力側は使われるシステムが特定の環境で定まっていない場合、より一般的なCRLFが良いでしょう。
- 入力側ではどの改行コードでも同様に受け付けるという方法が安全に思われるかもしれませんが、「レコード区切りをCRLF、項目内の改行をLFとして区別する」などがあり得ますので、出力側データを考慮した上で決定します。
- 例外的な場合も多くは囲み文字で囲われた改行コードはレコード区切りとして処理しないことで問題の回避が可能です。
- 問題発生時にも原因が分かりにくいため、読み込み側ではなるべくわかりやすくエラーを表示できるように努めます。
3. エスケープ処理
特殊なケースに対する対応方法を決めておきます。
- フィールド囲み文字内のエスケープ方法
- フィールド囲み文字をデータとしたい場合、そのままでは区別がつきません。
- ダブルクォートで囲まれたダブルクォートは重ねる
""
か別なエスケープ文字を設定してその後ろに置く\”
ことで区別します。
- 特殊文字のエスケープ
- 区切り文字や改行を含む場合は、フィールド囲み文字でフィールドを囲むことが一般的ですが、エスケープ文字を使用することもあります。
- エスケープ文字を設定する場合は、そのエスケープ文字もエスケープ (
) することを忘れないようにします。\\
- 特殊文字の排除
- これらをエスケープするのではなく、置き換えることで問題を回避する方法もあります。
- 元データと異なるため正確性が無くなりますが、出力側で対処しておくことで入力側での処理が無くてもトラブルになりません。
- 元データに特殊文字が一切入らないように設計することでも回避できますが、他の部分の設計に依存するのは安全性が担保できなくなります。
4. ヘッダーの扱い
結構システムによってバラツキがある部分ですので、しっかり設計に含めます。
- ファイルの先頭行にヘッダー行を含めるか否か
- 人が見ることが想定される場合は、ヘッダー行があったほうが分かりやすい場合があります。
- 日本語の無いデータや、桁数、項目数が多いものはあっても見づらい場合や、相手が理解できている際は不要かもしれません。
- 決まっていないとシステムで読み込む場合に障害となるため、取り決めが必要です。
- ヘッダー行の仕様 (固定か、キーとしての対応付けを必要とするか)
- ヘッダー付きの場合、これをフィールドのキーとして扱えるため、プログラムの書き方によっては便利なこともあります。
- キーとして扱う場合は、1文字違うだけで正しく動かないため、読み込み時にチェックを行うことをお勧めします。
5. ファイル末尾の扱い
意外とトラブルになることがあるため、ここも取り決めておきます。
- 余分な改行があるかどうか
- 最終データ行の末尾に改行があり、ファイルの終端であることが一般的です。
- 異なる設計では、最終行に改行が無いことでファイルの終端を示す場合や、最終行が改行のみである場合などがあります。
5. データ型
CSV自体の仕様では無く、内部に持つデータの形式も決めておきます。
- フィールドのデータ型 (文字列、数値、日付等)
- 最終的に出力されるデータは文字列ですが、取り扱う際に処理を決めておく必要があります。
- 数値のフォーマット (小数点の区切り文字、桁区切り、ゼロ埋め)
- 読み込むシステムなどによって求められる仕様が異なりますので、トラブルの起きないような形で出力するようにします。
- 読み込む側も、出力元システムの仕様が異なる可能性がある場合には柔軟に受け入れられるように設計すると良いでしょう。
- 日付のフォーマット (例:
YYYY-MM-DD
,MM/DD/YYYY
,DD-MM-YYYY
)- どちらかというと、文化圏により表記が異なるものですが、いずれにしても設計では確定しておく必要があります。
6. その他の処理
- エラーハンドリング
- 不正なフォーマットが含まれていた場合の処理を決めておきます。 (エラー出力、無視して続行、修正して続行)
- 空白の扱い
- フィールド値前後の空白の扱いを決めます。 (トリムするか、そのままにするか)
- コメント行の扱い
- コメント行の有無と識別方法を決定します。(例:# で始まる行をコメントとみなす)
7. 独自コードを書くのか
読み込むべきCSVファイが一般的な仕様でなかった場合、もしくは一般的でない仕様のCSVファイルを求められた場合には独自コードが必要かもしれません。
- 独自コードが必要でない場合は、すでにあるライブラリを利用し、その仕様を設計として書き出します。
- すでにあるライブラリでも詳細な仕様が示されていない場合は、内容から処理を確認して詳細な設計を記載する必要があります。
最後に
これらの項目に関して明確な仕様を定め、ドキュメント化した上で開発者全員が一貫して守ることにより、バイナリレベルで全く同じCSVファイル出力を保証することができます。
これらの仕様に従ったCSVファイルを生成するためのプログラムライブラリやフレームワークを用意し、開発者が利用することで、仕様の統一及び実装の正確性がさらに向上します。