DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

DataTableや配列等をCSV形式のファイルとして保存する

CSV形式の規則は、「CSV形式のファイルをDataTableや配列等として取得する」で紹介したものと同じとして、話を進めます。つまり、4,6の規則に従い、フィールドにカンマ、改行文字が含まれる場合は、ダブルクォートで囲みます。また5の規則に従い、フィールドにダブルクォートが含まれる場合は、これを2つのダブルクォートに置換して、ダブルクォートで囲みます。さらに規則7に従い、フィールドの前後にスペースがある場合も、ダブルクォートで囲みます。

このような方針により、DataTableをCSV形式のファイルに保存する例を以下に示します。フィールドの型を考慮せず、単純にToStringメソッドで文字列にして保存しています。ヘッダも書き込んでいますが、ヘッダの書き込みと、レコードの書き込みが全く同じコードになっており、コードとしてはあまり良くありません。あくまでサンプルということで、ご了承ください。

またこの例では、いちいち一つ一つのフィールドを調べてダブルクォートで囲むか調べていますが、これが面倒であれば、すべてのフィールドをダブルクォートで囲むようにしても結構です。

VB.NET
コードを隠すコードを選択
'CSVで保存するDataTable
Dim dt As DataTable = CType(DataGrid1.DataSource, DataTable)
'保存先のCSVファイルのパス
Dim csvPath As String = "C:\test1.csv"
'CSVファイルに書き込むときに使うEncoding
Dim enc As System.Text.Encoding = _
    System.Text.Encoding.GetEncoding("Shift_JIS")

'開く
Dim sr As New System.IO.StreamWriter(csvPath, False, enc)

Dim colCount As Integer = dt.Columns.Count
Dim lastColIndex As Integer = colCount - 1

'ヘッダを書き込む
Dim i As Integer
For i = 0 To colCount - 1
    'ヘッダの取得
    Dim field As String = dt.Columns(i).Caption
    '"で囲む必要があるか調べる
    If field.IndexOf(ControlChars.Quote) > -1 OrElse _
        field.IndexOf(","c) > -1 OrElse _
        field.IndexOf(ControlChars.Cr) > -1 OrElse _
        field.IndexOf(ControlChars.Lf) > -1 OrElse _
        field.StartsWith(" ") OrElse _
        field.StartsWith(ControlChars.Tab) OrElse _
        field.EndsWith(" ") OrElse _
        field.EndsWith(ControlChars.Tab) Then
        If field.IndexOf(ControlChars.Quote) > -1 Then
            '"を""とする
            field = field.Replace("""", """""")
        End If
        field = """" + field + """"
    End If
    'フィールドを書き込む
    sr.Write(field)
    'カンマを書き込む
    If lastColIndex > i Then
        sr.Write(","c)
    End If
Next i
'改行する
sr.Write(ControlChars.Cr + ControlChars.Lf)

'レコードを書き込む
Dim row As DataRow
For Each row In dt.Rows
    For i = 0 To colCount - 1
        'フィールドの取得
        Dim field As String = row(i).ToString()
        '"で囲む必要があるか調べる
        If field.IndexOf(ControlChars.Quote) > -1 OrElse _
            field.IndexOf(","c) > -1 OrElse _
            field.IndexOf(ControlChars.Cr) > -1 OrElse _
            field.IndexOf(ControlChars.Lf) > -1 OrElse _
            field.StartsWith(" ") OrElse _
            field.StartsWith(ControlChars.Tab) OrElse _
            field.EndsWith(" ") OrElse _
            field.EndsWith(ControlChars.Tab) Then
            If field.IndexOf(ControlChars.Quote) > -1 Then
                '"を""とする
                field = field.Replace("""", """""")
            End If
            field = """" + field + """"
        End If
        'フィールドを書き込む
        sr.Write(field)
        'カンマを書き込む
        If lastColIndex > i Then
            sr.Write(","c)
        End If
    Next i
    '改行する
    sr.Write(ControlChars.Cr + ControlChars.Lf)
Next row

'閉じる
sr.Close()
C#
コードを隠すコードを選択
//CSVで保存するDataTable
DataTable dt = (DataTable) dataGrid1.DataSource;
//保存先のCSVファイルのパス
string csvPath = "C:\\test1.csv";
//CSVファイルに書き込むときに使うEncoding
System.Text.Encoding enc =
    System.Text.Encoding.GetEncoding("Shift_JIS");

//開く
System.IO.StreamWriter sr =
    new System.IO.StreamWriter(csvPath, false, enc);

int colCount = dt.Columns.Count;
int lastColIndex = colCount - 1;

//ヘッダを書き込む
for (int i = 0; i < colCount; i++)
{
    //ヘッダの取得
    string field = dt.Columns[i].Caption;
    //"で囲む必要があるか調べる
    if (field.IndexOf('"') > -1 ||
        field.IndexOf(',') > -1 ||
        field.IndexOf('\r') > -1 ||
        field.IndexOf('\n') > -1 ||
        field.StartsWith(" ") || field.StartsWith("\t") ||
        field.EndsWith(" ") || field.EndsWith("\t"))
    {
        if (field.IndexOf('"') > -1)
        {
            //"を""とする
            field = field.Replace("\"", "\"\"");
        }
        field = "\"" + field + "\"";
    }
    //フィールドを書き込む
    sr.Write(field);
    //カンマを書き込む
    if (lastColIndex > i)
    {
        sr.Write(',');
    }
}
//改行する
sr.Write("\r\n");

//レコードを書き込む
foreach (DataRow row in dt.Rows)
{
    for (int i = 0; i < colCount; i++)
    {
        //フィールドの取得
        string field = row[i].ToString();
        //"で囲む必要があるか調べる
        if (field.IndexOf('"') > -1 ||
            field.IndexOf(',') > -1 ||
            field.IndexOf('\r') > -1 ||
            field.IndexOf('\n') > -1 ||
            field.StartsWith(" ") || field.StartsWith("\t") ||
            field.EndsWith(" ") || field.EndsWith("\t"))
        {
            if (field.IndexOf('"') > -1)
            {
                //"を""とする
                field = field.Replace("\"", "\"\"");
            }
            field = "\"" + field + "\"";
        }
        //フィールドを書き込む
        sr.Write(field);
        //カンマを書き込む
        if (lastColIndex > i)
        {
            sr.Write(',');
        }
    }
    //改行する
    sr.Write("\r\n");
}

//閉じる
sr.Close();

XSLTを使う方法

このような方法以外に、XSLTを使ってCSVに変換する方法もあります。この方法については、掲示板の過去ログの「DatasetのデータをCSV保存する」や、次のリンク先をご覧ください。

私個人の意見としましては、このような方法ではCSVの規則に従うファイルを出力するのが難しく、柔軟性にも乏しいため、お勧めはできません。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • このサイトで紹介されているコードの多くは、例外処理が省略されています。例外処理については、こちらをご覧ください。
  • Windows Vista以降でUACが有効になっていると、ファイルへの書き込みに失敗する可能性があります。詳しくは、こちらをご覧ください。