C#

【C#】CsvHelperでCSVファイルを読み込むする方法(サンプル有り)

C#でプログラムを開発していると、アプリケーションで CSV ファイルの読み込みをしなければならない場面がたまにあります。

単純に「カンマ(,)」で分割すればいいと思うかもしれませんが、CSVファイルの仕様て扱う現場によって結構バラバラだったりします。

こうなると単純に分割しただけではうまくいきません。

そこでオススメするライブラリが「CsvHelper」です。

この記事では、2022年4月時点で最新バージョンである CsvHelper を利用して CSV ファイルを読み込む方法について紹介しています。

CSVの仕様

CSVとは Comma Separated Values の略でカンマ区切りで並べた値という意味で、そのCSVの形式で保存されたファイルをCSVファイル(拡張子:*.csv)と言います。

CSVファイルはデータ交換用フォーマットとして最も普及したデータ交換用のフォーマットです。

広く利用されている割にCSVは明確な決まり事がなく、扱う場面によって仕様が異なる事が多々あります。

例えば、ファイルの先頭にはヘッダーとなる行があってもなくてもいいですし、ファイル末尾のレコードの終端には改行があってもなくてもいいのです。

他にも次のような項目で仕様が異なることがあります。

  • ヘッダー行
    ファイルの先頭にはヘッダー行があってもなくてもいい
  • ファイル末尾
    ファイル末尾の行の終端には改行があってもなくてもいい
  • CSVの値
    文字列は「”(ダブルクォーテーション)」で囲んでも囲まなくてもいい
    ※値の中に「,(カンマ)」や「改行<CR><LF>」など制御文字がある場合は「”」で囲む必要がある。
  • 区切り文字
    基本は「,(カンマ)」で区切るが、「タブ<TAB>」で区切ってもいい
  • 改行コード
    各行の改行は<CR><LF>とする。
    ※実行環境によって異なり、UNIXの場合は<LF>

C#でCSVファイルを読み取りする方法として、「,(カンマ)」を Split メソッドで分割して string 配列にする方法があります。

【C#】CSVファイルを1行ずつ読み込みする方法「C#でCSVファイルを読み込みたい」という方はこの記事を参考にしてみてください。CSVファイルを1行ずつ読み取りするには、StreamReaderクラスとSplitメソッドを組み合わせましょう。...

この方法は簡単に読み取りができる一方で、データの中にカンマがあるとそこで分割されてしまいます。この結果、読み取りしたデータが想定した通りに string 配列に入っていない場合があり、変換前にチェックする関数など用意してあげる必要があります。

こういう面倒なことをしたくない場合は「CsvHelper」というライブラリを利用するのがオススメです。さまざまな機能を有している為、仕様の違いに対して柔軟にCSVファイルの読み取りを行う事ができます。

では CsvHelper について詳しくみてみましょう。

CsvHelperとは

CsvHelperは、CSVファイルの読み取りと書き込みを行う為のオープンソースの .NET ライブラリです。非常に高速かつ柔軟に扱うことができます。

このライブラリは次のような特徴が挙げられます。

CsvHelperの特徴
  1. 商用利用可能なオープンソースライブラリである
  2. 柔軟にCSVファイルの読み取りができる
  3. CSVファイルをクラスへマッピングする機能がある

     

    商用利用可能なオープンソースライブラリである

    CsvHelper は NuGet からインストールする事が可能です。もちろん、前述している通り無料で利用ができます。

    インストール手順は次の通りです。

    STEP①
    Visual Studio の「ツール」 -> 「NuGet パッケージ マネージャー」 -> 「ソリューションの NuGet パッケージの管理」を選択します。

    STEP②
    「参照」タブを選択して、検索欄に「CsvHelper」と入力して表示された「CsvHelper」を選択します。

    STEP③
    チェックボックスにチェックを入れて、「インストール」ボタンをクリックします。

    ここでは、2022年4月時点で最新の安定版である 「27.2.1」 をインストールしています。

     

    柔軟にCSVファイルの読み取りができる

    CsvConfiguration のプロパティをいじくる事で様々な仕様に合わせた形でCSVファイルを読み取りすることができます。ここではよく使うプロパティについて紹介をしています。

    ヘッダー行の選択
    ファイルの先頭にはヘッダー行が有る場合と無い場合があります。

    ヘッダー有り
    ヘッダー無し

    Configuration の HasHeaderRecord プロパティで true または false を選択することで、ヘッダー行の読み込み設定ができます。

    //ヘッダー有り
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        HasHeaderRecord = true
    };
    
    //ヘッダー無し
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        HasHeaderRecord = false
    };
    

     

    区切りの選択
    CSVの区切り文字は基本的に「,(カンマ)」ですが、それ以外の制御文字が使われている場合があります。例えば、「スペース」や「セミコロン」がカンマの代わりとして使われる場合があります。

    区切り文字:カンマ
    区切り文字:スペース

    Configuration の Delimiter プロパティで区切り文字を選択することができます。

    //カンマ区切り
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        Delimiter = ","
    };
    
    //スペース区切り
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        Delimiter = "U+002C"
    };
    

     

    改行コードの選択
    ファイルの改行コードが実行環境によって異なる場合があります。改行コードには、「\r\n」「\r」「\n」があります。

    Configuration の NewLine プロパティで適切な改行コードに設定することで正確にCSVの読み込みを行うことができます。

    //改行コード \r\n
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        NewLine = "\r\n",
    };
    
    //実行環境で定義されている改行コード
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        NewLine = Environment.NewLine,
    };
    

     

    空行の無視の有無
    CSVファイルに空白行があった場合に読み取りをするかしないかを設定できます。

    Configuration の IgnoreBlankLines プロパティが true の場合は無視をして次の行を読み取りし、falseの場合は読み取りをします。

    //空白を無視する
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        IgnoreBlankLines = true,
    };
    
    //空白を無視しない
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        IgnoreBlankLines = false,
    };

     

    エンコードの選択
    エンコードとは簡単に言うと、ある規則に基づいてデータを変換することです。CSVファイルもこのエンコードに基づいてデータが保存されています。

    CSVを読み取りする際、エンコードが異なると文字化けが発生する可能性があります。

    Configuration の Encoding プロパティで適切なエンコードに設定しておきましょう。

    // UTF-8
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        Encoding = Encoding.UTF8,
    };
    
    // ASCII(7ビット)
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        Encoding = Encoding.ASCII,
    };

     

    コメントの有無
    CSVファイル内にコメントが記入されていることがあります。CsvHelperではコメントの有無を設定することができます。

    Configuration の AllowComments プロパティが true ならコメントを許可し、falseの場合はコメントを拒否します。

    また、先頭の文字列にはコメントを意味する文字列が必ずあるので、Comment プロパティでその文字列を設定します。

    // コメント許可
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        AllowComments = true,
        Comment = '#',
    };
    
    // コメント拒否
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        AllowComments = false,
    };
    

     

    列のフィールドの増減チェック
    列のフィールドが前後データフィールドが異なる場合があります。もしくはCSVファイルを編集した時にフィールドを誤って消したり、増やしてしまう場合があります。

    列数をチェックするには Configuration の DetectColumnCountChanges プロパティを true にします。列数が異なる行を検出したら例外(CsvHelper.BadDataException)が発生します。

    列数のチェックをしない場合は、false にします。

    // 列数をチェックする
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        DetectColumnCountChanges = true,
    };
    
    
    // 列数をチェックしない
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        DetectColumnCountChanges = false,
    };

     

    フィールドの前後の空白削除
    フィールド内に存在する空白を取り除くには、 Configuration の TrimOptions プロパティを設定します。

    // 空白を削除
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        TrimOptions = TrimOptions.Trim,
    };

     

    CSVファイルをクラスへマッピングする機能

    CSVファイルの列をクラスのどのプロパティにセットするかを簡単に管理することができます。

    プロパティの位置をインデックスの位置と紐づけをして使用します。

    この方法については後述で詳しく記載しています。

     

    CsvHelperの使い方

    それではC#でCSVファイルを読み込む方法をサンプルを交えながら紹介をします。

    CsvHelperは更新頻度が高いため、インターネットで検索するサンプルは前のバージョンで動作するものが多く、ライブラリの最新バージョンをダウンロードするとサンプルをコピペしても動かないなんてことがあります。

    ここで紹介するサンプルは2022年4月時点で最新の安定版である「27.2.1」を使っています。

    CSVのサンプルファイル

    ここで使うサンプルは次のようなCSVファイルです。

    1行目はヘッダー(項目名)があり、2行目はコメントがあります。

    3行目から7行目までフィールドで、フィールド内に空白を含むデータや6行目には空白行が存在します。

    no,name,birthDay,bloodType
    #ここからフィールドです。
    1,"広瀬すず","6月19日","AB"
    2 ,福山雅治 ,2月6日 ,O 
     3,菅田将暉 ,2月21日 ,A
    
    4,長澤まさみ,6月3日,A

     

    CSVの読み取り

    CSVのフィールドをプロパティにセットするクラスを作成します。

    この時、CSVの1列がクラスの1つのプロパティとマッピングされるようにします。どの列のフィールドをどのプロパティにデータを渡すかを指定するには Attributes(属性)を使います。

    属性はインデックスまたはヘッダー名を使用することができます。ただし、ヘッダー名を属性とする場合はCSVファイルに1行目にヘッダーが存在する場合に限ります。

    属性:インデックス
    using CsvHelper.Configuration.Attributes;
    
    public class Foo
    {
        [Index(0)]
        public int No { get; set; }            //No
    
        [Index(1)]
        public string Name { get; set; }       //名前
    
        [Index(2)]
        public string BirthDay { get; set; }   //誕生日
    
        [Index(3)]
        public string BloodType { get; set; }  //血液型
    }
    属性:ヘッダー名
    using CsvHelper.Configuration.Attributes;
    
    public class Foo
    {
        [Name("no")]
        public int No { get; set; }            //No
    
        [Name("name")]
        public string Name { get; set; }       //名前
    
        [Name("birthDay")]
        public string BirthDay { get; set; }   //誕生日
    
        [Name("bloodType")]
        public string BloodType { get; set; }  //血液型
    }

     

    CSVファイルを読み取りするサンプルコードは次の通りです。関数の引数として、CSVのファイル名を渡します。

    public void ReadCsvFile(string fileName)
    {
        var config = new CsvConfiguration(CultureInfo.InvariantCulture)
        {
            HasHeaderRecord = true,
            Delimiter = ",",
            NewLine = Environment.NewLine,
            IgnoreBlankLines = true,
            Encoding = Encoding.UTF8,
            AllowComments = true,
            Comment = '#',
            DetectColumnCountChanges = true,
            TrimOptions = TrimOptions.Trim,
        };
    
        using (var reader = new StreamReader(fileName, Encoding.UTF8))
        using (var csv = new CsvReader(reader, config))
        {
            var records = csv.GetRecords();
    
            foreach (var record in records)
            {
                Debug.WriteLine("----------------------------");
                Debug.WriteLine($"No:{record.No}");
                Debug.WriteLine($"Name:{record.Name}");
                Debug.WriteLine($"Birth Day:{record.BirthDay}");
                Debug.WriteLine($"Blood Type:{record.BloodType}");
            }
        }
    }
    サンプルコードの実行結果

    —————————-
    No:1
    Name:広瀬すず
    Birth Day:6月19日
    Blood Type:AB
    —————————-
    No:2
    Name:福山雅治
    Birth Day:2月6日
    Blood Type:O
    —————————-
    No:3
    Name:菅田将暉
    Birth Day:2月21日
    Blood Type:A
    —————————-
    No:4
    Name:長澤まさみ
    Birth Day:6月3日
    Blood Type:A

    このようにCSVを読み込むことができます。

    今回オプションで空白行はスキップ、フィールドの空白の削除を行っています。実行結果からオプションで指定した通りに読み取りができていることが分かります。

    まとめ

    この記事ではCsvHelperを使ってCSVファイルを読み込む方法について紹介しました。

    CsvHelperは仕様が曖昧なCSVファイルでも、Configuration クラスのプロパティを設定することで、柔軟にCSVを読み込めるオススメの無料ライブラリです。

    また、CSVファイルの列をクラスのどのプロパティにセットするかを簡単に管理できるので、是非活用してみてください。

    以上、最後まで読んで頂きありがとうございました。

    プログラミングを学習したいなら…

    プログラミングスキルを身に付けるなら、プログラミングを効率良く学べる
    プログラミングスクール」がオススメです。

    特にこんな方にオススメ!!
    これからエンジニアを目指したい
    プログラミングの専門性を高めたい
    プログラミングを学んで副業をしたい
    エンジニアに転職して年収をアップさせたい

    プログラミングを触ったことがない未経験からでも、プログラミングスクールで学習すれば、エンジニアへ就職・転職することも可能です。

    あなたの「行動力」と「やる気」で、あなたの人生を大きく変えるチャンスになることでしょう。

    プログラミングスクールに興味がある方は是非チェックしてみてください。

    > プログラミングを学ぶ <

    COMMENT

    メールアドレスが公開されることはありません。

    CAPTCHA