はじめに
最近関わったプロジェクトで出くわしたCSV処理について、備忘の意味も込めて書きます。
恐らく今時こんな書き方をしている箇所を見ることはないだろうけど、参考までに。
何をしたかったのか
内容はいたってシンプルで、システムの既存機能として存在しているCSV取り込み
に手を加えるというもの。
具体的には、CSVのフォーマットが変わって、取り込むデータが1列増えたので対応する。
既存のCSVはA列、B列、C列、D列
というフォーマットだが、今回はB列とC列の間にBα列を追加
したいとのこと。
ソース
メソッド名等々は適当にぼかしてあります。
using Microsoft.VisualBasic.FileIO;
// ...略
private void LoadCsv(string csvPath){
// TextFieldParserでCSVを読み込み
TextFieldParser parser = new TextFieldParser(csvPath, Encoding.GetEncoding("shift_jis"));
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
while (parser.EndOfData == false) {
string[] datas = parser.ReadFields();
int cols = datas.length;
// 列数が不正だったら終了
if(cols != 4){
return;
}
// A列処理
if(string.IsNullOrEmpty(datas[0])){
// ...略
}
// B列処理
if(string.IsNullOrEmpty(datas[1])){
// ...略
}
// C列処理
if(string.IsNullOrEmpty(datas[2])){
// ...略
}
// D列処理
if(string.IsNullOrEmpty(datas[3])){
// ...略
}
// 取得したデータをDBに書き込んだり...
// その結果を画面に表示させたり...
}
}
ぼく「うわぁ・・・、まじかよ・・・」
見ての通り取り込むCSVのフォーマットに合わせてインデックスをハードコーディングしてあるので、先に書いた通りB列とC列の間にBα列を追加
するとなると、C列はdatas[2]
ではなくdatas[3]
になり、D列は・・・
といった風に、Bα列以降のインデックスをインクリメントしないといけなくなってくる。
もっと言うと、合計列数は4から5になるので列数不正となる条件はif(cols != 4)
からif(cols != 5)
になる。
まだ元々のフォーマットが4列だったから良かったものの、もしこれが10数列もあったら・・・と考えるとゾッとする。
というわけで、以下のようにCSVのインデックスをenum
で持たせることにしました。
// 列のインデックス定義
private enum CsvCols
{
// A列
ColA = 0,
// B列
ColB = 1,
// Bα列
ColBalpha = 2,
// C列
ColC = 3,
// D列
ColD = 4
}
// 列数
private static int CSV_COLS = Enum.GetNames(typeof(CsvCols)).Length;
そんでもって、各インデックスのハードコーディング箇所を以下のように修正
// 列数が不正だったら終了(修正前)
//if(cols != 4){
// return;
//}
// 列数が不正だったら終了(修正後)
if(cols != CSV_COLS){
return;
}
// A列処理(修正前)
//if(string.IsNullOrEmpty(datas[0])){
// // ...略
//}
// A列処理(修正後)
if(string.IsNullOrEmpty(datas[(int)CsvCols.ColA])){
// ...略
}
おわりに
これなら今後対象となるCSVのフォーマットが変わっても、enumの中身を変える(追加・削除する)だけで対応できます。
もしかしたらもっといいやり方があるのかもしれない(あったら教えてください)