2014/03/15

【C#】ダブルクォーテーションで括ってCSVを出力する(Listクラスを弄る)

DBからデータを抽出し、編集してCSVに出力する簡単な機能。
今回はGenericのListクラスを継承しAddメソッドを弄ることで、ダブルクォーテーションを付加しながらCSVを出力するプログラムを作った。

Collections.Generic.List<T>クラスは拡張性を犠牲にしてパフォーマンスを優先している。
そのため、継承して使うのは推奨されていないっぽい。

System.Collections.Generic.List は、継承ではなくパフォーマンスを目的としたジェネリック コレクションです。 System.Collections.Generic.List には、継承クラスの動作を変更しやすくする仮想メンバーは含まれていません。引用元:CA1002: ジェネリック リストを公開しません – MSDN

でも、コンマ何秒の性能を重視するようなプログラムじゃないし、ちょっとくらいいいよね?
CSharperの先輩たちに見せたら怒られるかな?


Listクラスを継承してダブルクォーテーションで括る



まずはバッチ本体。ありきたりなループ処理。
static void Main(string[] args)
{
    StreamWriter sw = new StreamWriter("C:\test.csv", false, Encoding.UTF-8)
    
    foreach (なんかのループ)
    {
        CsvList<string> csvList = new CsvList<string>();

        // 勝手にダブルクォーテーションでくくってくれる
        csvList.Add("文字列");
        csvList.Add("文字列");
        csvList.Add("文字列");

        // 書き込み
        sw.WriteLine(String.Join(",", csvList.ToArray()));
    }
    sw.Dispose();
}

次に、Listクラスを継承したCsvListクラス

public class void CsvList<T> : System.Collections.Generic.List<string>
{
    // ListのAddを隠蔽し再定義(orverrideできないため)
    public new void Add(string item)
    {
        // ダブルクォーテーションで文字列を囲む
        base.Add("\"" + item + "\"");
    }
}



基礎:DBの値を取得して、CSVを出力する



なぜListクラスなんかを継承したのか。
単純にDBの値を取得して、そのままCSVを書き出すなら以下のプログラムでも良い。

// DB接続してデータを取得する処理(省略)

StreamWriter sw = new StreamWriter("C:\test.csv", false, Encoding.UTF-8);

List<String> csvLine = new List<String>();

// dtはDataTable
foreach (DataRow row in dt.Rows)
{
    csvLine = new List();
    for (int i; i < row.count; i++)
    {
        csvLine.Add("\"" + row[i].ToString() + "\""));
    }
    sw.WriteLine(String.Join(",", csvLine.ToArray());
}
sw.Dispose();

ただ、今回はそのままCSVに書き出すのではなく、編集や順番を変えて出力しなければいけなかったため、
csvLine.Add("\"" + row[i].ToString() + "\""));
の部分が、
csvLine.Add("\"" + row[”aaa”].ToString() + "\""));
csvLine.Add("\"" + row["bbb"].ToString() + "\""));
csvLine.Add("\"" + row["ccc"].ToString() + "\""));
csvLine.Add("\"" + row["ddd"].ToString() + "\""));
というように300行くらい続いていた。
中には、単純に設定するだけでなくいろんな編集処理が混ざっており、美しくないと感じた。



おまけ



上記プログラムでは文字列結合に「+」を使用しているが、String.Concatの方が早いらしい。
ループ内でいっぱい結合するならStringBuilderの方が良い。

後日談だが、要件では「CSVファイルを出力して欲しい」って聞いてたのに、完成間近に無慈悲な仕様変更が発生。


客:やっぱ固定長ファイルでよろ~♪ 
  CSVを固定長に変えるくらい簡単っしょ?




は?(ブチツ




これもいい機会なので、後日「C#で固定長ファイルを出力する」というエントリを書こうと思う。


転んでもタダで起きてたまるか!!




以上

0 件のコメント :

コメントを投稿