朧の.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;

        //dt:データを入れるDataTable
        //hasHeader:CSVの一行目がカラム名かどうか
        //fileName:ファイル名
        //separator:カラムを分けている文字(,など)
        //quote:カラムを囲んでいる文字("など)
        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);
            }
            //ファイルを閉じる
            parser.Close();
        }
        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
        //ファイルを閉じる
        parser.Close()
    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,こんばんは,今晩は








良いやや良い普通やや悪い悪い
14 2 103 2 6

投稿日時評価コメント
2023/12/20 普通 12,34,56,あいう
2023/03/02 普通 管理者により削除されました。
2023/02/22 普通 No,ひらがな,漢字 1,おはよう,お早う 2,こんにちは,今日は
2023/02/11 普通 管理者により削除されました。
2023/01/11 普通 ありがとうございます。頑張ります
2023/01/11 良い 大変分かりやすかったです。 VisualStudio2010で実装可能でしょうか
2023/01/10 管理人 コメントありがとうございます。 管理人です。 可能ですよ。頑張ってください。
2023/01/10 良い 大変分かりやすかったです。 VisualStudio2010で実装可能でしょうか
2023/01/10 良い 大変分かりやすかったです。 VisualStudio2010で実装可能でしょうか
2022/08/29 良い ナイス
2022/04/20 管理人 管理人です。エラーの確認はしてないのですが、多分その通りです。修正しておきます。 情報ありがとうございます。
2022/04/20 やや悪い リード後にMoveFile処理するとエラーになりませんか?(VB2019.NET環境で実施)57行にparser.Close処理を追加で解決した。ファイルがオープンのままなのでは?
2022/04/14 普通 ありがとうございます。
2022/03/30 普通 No,ひらがな,漢字 1,おはよう,お早う 2,こんにちは,今日は 3,こんばんは,今晩は
2022/01/04 普通
2021/11/20 やや良い あああ
2021/11/03 良い No,ひらがな,漢字 1,おはよう,お早う 2,こんにちは,今日は 3,こんばんは,今晩は
2021/10/27 普通 No,ひらがな,漢字 1,おはよう,お早う 2,こんにちは,今日は 3,こんばんは,今晩は
2021/08/16 普通 No,ひらがな,漢字 1,おはよう,お早う 2,こんにちは,今日は 3,こんばんは,今晩は
2021/08/16 普通 No,ひらがな,漢字 1,おはよう,お早う 2,こんにちは,今日は 3,こんばんは,今晩は
2021/04/07 普通 No,ひらがな,漢字 1,おはよう,お早う 2,こんにちは,今日は 3,こんばんは,今晩は
2020/12/24 普通 あああ
2016/07/03 管理人 貴重な情報ありがとうございます。 私の知らない情報でした。 検索すると結構有名な話のようですね。 ありがとうございます。
2016/07/03 やや悪い フィールド内の空行を無視する問題を説明してない。