C# で Listデータ を CSVファイル へ 書き込む 方法

0 件のコメント

Listデータ を CSVファイル へ書き込むサンプルコードを作成しました。 読み込みがあるから書き込みもと思って作りましたが、単純に実装しています。

CSVフォーマットの仕様に関してはざっくりと CSVフォーマット の 仕様 に記載しました。

目次

サンプルコード

受け取ったListデータをカンマ区切り(CSV)で出力します。

以下にあるコードをダブルクリックして選択、コピペすれば使える ハズ です。

CsvWriter.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;

/// <summary>
/// CSV形式のストリームを書き込む CsvWriter を実装します。
/// </summary>
public class CsvWriter : IDisposable
{
    /// <summary>
    /// CSVファイルに書き込むストリーム
    /// </summary>
    private StreamWriter stream = null;

    /// <summary>
    /// ファイル名を指定して、 <see cref="CsvWriter">CsvWriter</see> クラスの新しいインスタンスを初期化します。
    /// </summary>
    /// <param name="path">書き込む完全なファイルパス。</param>
    public CsvWriter(string path) :
        this(path, Encoding.Default)
    {
    }

    /// <summary>
    /// ファイル名、文字エンコーディングを指定して、 <see cref="CsvWriter">CsvWriter</see> クラスの新しいインスタンスを初期化します。
    /// </summary>
    /// <param name="path">書き込む完全なファイルパス。</param>
    /// <param name="encoding">使用する文字エンコーディング。</param>
    public CsvWriter(string path, Encoding encoding)
    {
        var stream = new FileStream(path, FileMode.Create, FileAccess.ReadWrite);
        this.stream = new StreamWriter(stream, encoding);
    }

    /// <summary>
    /// 使用する文字エンコーディングを取得します。
    /// </summary>
    public Encoding Encoding
    {
        get
        {
            return this.stream.Encoding;
        }
    }

    /// <summary>
    /// 現在のストリームで利用される改行文字列を取得または設定します。
    /// </summary>
    public string NewLine
    {
        get
        {
            return this.stream.NewLine;
        }

        set
        {
            this.stream.NewLine = value;
        }
    }

    /// <summary>
    /// 現在のストリームオブジェクトと基になるストリームをとじます。
    /// </summary>
    public void Close()
    {
        if (this.stream == null)
        {
            return;
        }

        this.stream.Close();
    }

    /// <summary>
    /// CsvWriter で利用されているすべてのリソースを解放します。
    /// </summary>
    public void Dispose()
    {
        if (this.stream == null)
        {
            return;
        }

        this.stream.Close();
        this.stream.Dispose();
        this.stream = null;
    }

    /// <summary>
    /// 現在のライターで使用したすべてのバッファーをクリアし、バッファー内のすべてのデータをストリームに書き込みます。
    /// </summary>
    public void Flush()
    {
        this.stream.Flush();
    }

    /// <summary>
    /// 現在のライターで使用したすべてのバッファーを非同期的にクリアし、ストリームへ書き込みます。
    /// </summary>
    /// <returns>非同期のフラッシュ操作を表すタスク。</returns>
    public Task FlushAsync()
    {
        return this.stream.FlushAsync();
    }

    /// <summary>
    /// ストリームに文字を書き込みます。
    /// </summary>
    /// <typeparam name="T">リストの型。</typeparam>
    /// <param name="data">CSVデータ。</param>
    public void Write<T>(List<List<T>> data)
    {
        foreach (var row in data)
        {
            this.WriteRow<T>(row);
        }
    }

    /// <summary>
    /// ストリームに文字を非同期的に書き込みます。
    /// </summary>
    /// <typeparam name="T">リストの型。</typeparam>
    /// <param name="data">CSVデータ。</param>
    /// <returns>非同期の書き込み操作を表すタスク。</returns>
    public Task WriteAsync<T>(List<List<T>> data)
    {
        return Task.Factory.StartNew(() =>
        {
            this.Write<T>(data);
        });
    }

    /// <summary>
    /// ストリームに1レコード分の文字列を書き込みます。
    /// </summary>
    /// <typeparam name="T">リストの型。</typeparam>
    /// <param name="row">CSVの1レコード。</param>
    public void WriteRow<T>(List<T> row)
    {
        var sb = new StringBuilder();

        foreach(var cell in row)
        {
            var value = cell.ToString();

            if (value.Contains(this.NewLine) ||
                value.Contains(",") ||
                value.Contains("\""))
            {
                value = value.Replace("\"", "\"\"");
                sb.Append("\"");
                sb.Append(value);
                sb.Append("\"");
            }
            else
            {
                sb.Append(value);
            }

            sb.Append(",");
        }

        sb.Remove(sb.Length - 1, 1);
        
        this.stream.WriteLine(sb.ToString());
    }

    /// <summary>
    /// ストリームに1レコード分の文字列を非同期的に書き込みます。
    /// </summary>
    /// <typeparam name="T">リストの型。</typeparam>
    /// <param name="row">CSVの1レコード。</param>
    /// <returns>非同期の書き込み操作を表すタスク。</returns>
    public Task WriteRowAsync<T>(List<T> row)
    {
        return Task.Factory.StartNew(() =>
        {
            this.WriteRow<T>(row);
        });
    }
}

使用例

上記サンプルコードの利用例を以下に載せます。 サンプルコードには非同期メソッドも実装しましたが、ここでは同期メソッドの使用例だけあげます。

すべてのデータを書き込む使用例

using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
            var data = new List<List<int>>()
            {
                new List<int>(){1,2,3,4,5},
                new List<int>(){1,1,1,1,1}
            };

            using (var writer = new CsvWriter(@"hoge.csv"))
            {
                writer.Write(data);
            }
    }
}

関連記事