朧の.Netの足跡
問合せ先:support@oborodukiyo.info サイト内検索はこちら 
基本 CSVファイルをDataTableに読み込んで表示する





ここでは、CSVをDataTableに読み込んで、DataGridViewに表示しています。 ちょっと難しいところもあるかもしれないのでコメントを多めに入れています。
ポイントはCSVファイルを読み込むためにTextFieldParserクラスを使用しているところです。 これでCSVの中のフォーマットチェックをすることなく読み込めます。
DataTableのデータをCSVファイルに保存するのは、DataTableをCSVにして保存で紹介しているSaveToCSVメソッドを呼び出していますので、 このフォームのクラスなりにこのメソッドを追加して使用してください。
Visual Studio 2010版はこちらを参考にしてみてください。

(注)TextFieldParserクラスは何も書かれてない行があるとそこは飛ばして結果に表示されない動きをします。
多くの方はこれは好ましくない動作であると捉えているようですが私は悪い動作だとは思いません。
例えば最後のデータがある行でそれと同じ行にEOFがない場合、つまり最後の行がEOFだけの行があった場合、現在の動作であれば空のデータが表示されないので良い動作だと思います。
もし空行を飛ばさない場合はこの場合においては空のデータが最後に表示されてしまいます。
空のデータが必要ならば、きちんとそのCSVのフォーマットに沿った空データを挿入するのが良いと思います。

C#の例

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
//プロジェクトの参照設定でMicrosoft.VisualBasicを設定してください。
using Microsoft.VisualBasic.FileIO;
        private void ReadCSV(DataTable dt, bool hasHeader, string fileName,string separator, bool quote)
        {
            //CSVを便利に読み込んでくれるTextFieldParserを使います。
            TextFieldParser parser = new TextFieldParser(fileName, Encoding.GetEncoding("shift_jis"));
            //これは可変長のフィールドでフィールドの区切りのマーカーが使われている場合です。
            //フィールドが固定長の場合は
            //parser.TextFieldType = FieldType.FixedWidth;
            parser.TextFieldType = FieldType.Delimited;
            //区切り文字を設定します。
            parser.SetDelimiters(separator);
            //クォーテーションがあるかどうか。
            //但しダブルクォーテーションにしか対応していません。シングルクォーテーションは認識しません。
            parser.HasFieldsEnclosedInQuotes = quote;
            string[] data;
            //ここのif文では、DataTableに必要なカラムを追加するために最初に1行だけ読み込んでいます。
            //データがあるか確認します。
            if (!parser.EndOfData)
            {
                //CSVファイルから1行読み取ります。
                data = parser.ReadFields();
                //カラムの数を取得します。
                int cols = data.Length;
                if (hasHeader)
                {
                    for (int i = 0; i < cols; i++)
                    {
                        dt.Columns.Add(new DataColumn(data[i]));
                    }
                }
                else
                {
                    for (int i = 0; i < cols; i++)
                    {
                        //カラム名にダミーを設定します。
                        dt.Columns.Add(new DataColumn());
                    }
                    //DataTableに追加するための新規行を取得します。
                    DataRow row = dt.NewRow();
                    for (int i = 0; i < cols; i++)
                    {
                        //カラムの数だけデータをうつします。
                        row[i] = data[i];
                    }
                    //DataTableに追加します。
                    dt.Rows.Add(row);
                }
            }
            //ここのループがCSVを読み込むメインの処理です。
            //内容は先ほどとほとんど一緒です。
            while (!parser.EndOfData)
            {
                data = parser.ReadFields();
                DataRow row = dt.NewRow();
                for (int i = 0; i < dt.Columns.Count; i++)
                {
                    row[i] = data[i];
                }
                dt.Rows.Add(row);
            }
        }
        private void btnOpen_Click(object sender, EventArgs e)
        {
            bool quote = false;
            string separator = "";
            switch (this.cmbQuote.SelectedIndex)
            {
                case 0:
                case 1:
                    //クォーテーションあり
                    quote = true;
                    break;
                case 2:
                    //クォーテーションなし
                    quote = false;
                    break;
            }
            switch (this.cmbSeparator.SelectedIndex)
            {
                case 0:
                    //カンマ区切り
                    separator = ",";
                    break;
                case 1:
                    //タブ区切り
                    separator = "\t";
                    break;
                case 2:
                    //スペース区切り
                    separator = " ";
                    break;
            }
            if (this.openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                this.dt.Columns.Clear();
                this.dt.Clear();
                ReadCSV(this.dt, this.ckOutputColumnName.Checked, this.openFileDialog1.FileName, separator, quote);
                this.dataGridView1.DataSource = this.dt;
            }
        }

VB.NETの例

'プロジェクトの参照設定でMicrosoft.VisualBasicを設定してください。
Imports Microsoft.VisualBasic.FileIO
    'dt:データを入れるDataTable
    'hasHeader:CSVの一行目がカラム名かどうか
    'fileName:ファイル名
    'separator:カラムを分けている文字(,など)
    'quote:カラムを囲んでいる文字("など)
    Private Sub ReadCSV(ByVal dt As DataTable, ByVal hasHeader As Boolean, ByVal fileName As String, ByVal separator As String, ByVal quote As Boolean)
        'CSVを便利に読み込んでくれるTextFieldParserを使います。
        Dim parser As TextFieldParser = New TextFieldParser(fileName, Encoding.GetEncoding("shift_jis"))
        'これは可変長のフィールドでフィールドの区切りのマーカーが使われている場合です。
        'フィールドが固定長の場合は
        'parser.TextFieldType = FieldType.FixedWidth;
        parser.TextFieldType = FieldType.Delimited
        '区切り文字を設定します。
        parser.SetDelimiters(separator)
        'クォーテーションがあるかどうか。
        '但しダブルクォーテーションにしか対応していません。シングルクォーテーションは認識しません。
        parser.HasFieldsEnclosedInQuotes = quote
        Dim data() As String
        'ここのif文では、DataTableに必要なカラムを追加するために最初に1行だけ読み込んでいます。
        'データがあるか確認します。
        If Not parser.EndOfData Then
            'CSVファイルから1行読み取ります。
            data = parser.ReadFields()
            'カラムの数を取得します。
            Dim cols As Integer = data.Length
            If hasHeader Then
                For i As Integer = 0 To cols - 1 Step 1
                    dt.Columns.Add(New DataColumn(data(i)))
                Next i
            Else
                For i As Integer = 0 To cols - 1 Step 1
                    'カラム名にダミーを設定します。
                    dt.Columns.Add(New DataColumn())
                Next i
                'DataTableに追加するための新規行を取得します。
                Dim row As DataRow = dt.NewRow()
                For i As Integer = 0 To cols - 1 Step 1
                    'カラムの数だけデータをうつします。
                    row(i) = data(i)
                Next i
                'DataTableに追加します。
                dt.Rows.Add(row)
            End If
        End If
        'ここのループがCSVを読み込むメインの処理です。
        '内容は先ほどとほとんど一緒です。
        While Not parser.EndOfData
            data = parser.ReadFields()
            Dim row As DataRow = dt.NewRow()
            For i As Integer = 0 To dt.Columns.Count - 1 Step 1
                row(i) = data(i)
            Next i
            dt.Rows.Add(row)
        End While
    End Sub
    
    Private Sub btnRead_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRead.Click
        Dim quote As Boolean = False
        Dim separator As String = ""
        Select Me.cmbQuote.SelectedIndex
            Case 0 To 1
                'クォーテーションあり
                quote = True
            Case 2
                'クォーテーションなし
                quote = False
        End Select
        Select Me.cmbSeparator.SelectedIndex
            Case 0
                'カンマ区切り
                separator = ","
            Case 1
                'タブ区切り
                separator = "\t"
            Case 2
                'スペース区切り
                separator = " "
        End Select
        If Me.openFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
            Me.dt.Columns.Clear()
            Me.dt.Clear()
            ReadCSV(Me.dt, Me.ckOutputColumnName.Checked, Me.OpenFileDialog1.FileName, separator, quote)
            Me.DataGridView1.DataSource = Me.dt
        End If
    End Sub

例えば以下のようなsample.csvファイルを使って読み込みと保存を試せます。

No,ひらがな,漢字
1,おはよう,お早う
2,こんにちは,今日は
3,こんばんは,今晩は








良いやや良い普通やや悪い悪い
13 2 61 2 5

投稿日時評価コメント
7/3/2016 8:52:23 PM 普通 貴重な情報ありがとうございます。 私の知らない情報でした。 検索すると結構有名な話のようですね。 ありがとうございます。
7/3/2016 4:42:03 AM やや悪い フィールド内の空行を無視する問題を説明してない。
10/28/2015 11:42:04 AM 良い たいへんたすかりました!!
良い ほぼコピペで使用することができました。 困っていたので助かりました^^
良い ほぼコピペで使用することができました。 困っていたので助かりました^^