ヘッダー付きのC#でのCSVファイルの解析


266

C#でCSVファイルを解析するデフォルト/公式/推奨される方法はありますか?自分のパーサーをロールバックしたくありません。

また、ODBC / OLE DBを使用してテキストドライバー経由でCSVを読み取る例もありましたが、多くの人々は、その「欠点」のためにこれを思いとどまらせました。これらの欠点は何ですか?

理想的には、最初のレコードをヘッダー/フィールド名として使用して、列名でCSVを読み取る方法を探しています。与えられた答えの一部は正しいですが、基本的にはファイルをクラスに逆シリアル化するように機能します。

回答:


138

ライブラリにすべての詳細を処理させてください!:-)

FileHelpersをチェックして、乾いたままにしてください-自分で繰り返してはいけません-車輪を何億回も再発明する必要はありません...

基本的には、パブリッククラス(およびデフォルト値、NULL値の置換などの十分に検討された属性)を使用して、データのその形状(CSVの個々の行のフィールド)を定義する必要があるだけです。 FileHelpersエンジンのファイルとビンゴ-そのファイルからすべてのエントリを取得します。1つの簡単な操作-優れたパフォーマンス!


1
FileHelpersあなたが本当にカスタムSTH必要が(そしてそのほとんどはとにかく拡張機能として実装することが可能)になるまでは、本当に便利な、はるかに行くための最良の方法ですテストしても解決策を行う
mikus

3
2015年6月1日の時点で、FileHelpersをダウンロードできる唯一の方法は、sourceforge.netで検索することでした。ここで使用するリンクがあります:sourceforge.net/projects/filehelpers/?source=directory
Sudhanshuミシュラ

2
@dotnetguyはリリース3.1(現在は3.1-rc2)に向かっています。また、サイトを再設計しました。www.filehelpers.netから最新バージョンをダウンロードできます
Marcos Meli

1
@MarcosMeliありがとうございます!私はすでにプロジェクトの1つでFileHelpersを使用しており、チームへの称賛を使用するのは簡単でした。私はすぐにそれについてブログを計画しています-ところで-新しいサイトが大好きです-よくやった!
Sudhanshu Mishra 2015

FileHelpersは、CSVで引用符で囲まれたコンマを適切に処理せず、実際にはフィールドヘッダーをマップします。代わりに、列が型で宣言されているのと同じ順序であると想定しています。個人的には使用しません。
Alastair Maw

358

CSVパーサーが.NET Frameworkの一部になりました。

Microsoft.VisualBasic.dllへの参照を追加します(C#では問題なく動作しますが、名前は問題ありません)。

using (TextFieldParser parser = new TextFieldParser(@"c:\temp\test.csv"))
{
    parser.TextFieldType = FieldType.Delimited;
    parser.SetDelimiters(",");
    while (!parser.EndOfData)
    {
        //Process row
        string[] fields = parser.ReadFields();
        foreach (string field in fields)
        {
            //TODO: Process field
        }
    }
}

ドキュメントはこちら-TextFieldParserクラス

PS CSV エクスポーターが必要な場合は、CsvExportを試してくださいdiscl:私は貢献者の1人です)


2
私の経験から、TextFieldParserは大きな(例:250Mbを超える)ファイルではうまく機能しません。:(
MBoros 2014年

6
TextFieldParserはIDisposableを実装しているため、using句で使用するのが最善です。そうでなければ良い答え。
Chris Bush

3
コンストラクタでは、次のように、デフォルトとは異なるエンコーディングを使用する場合があります。new TextFieldParser( "c:\ temp \ test.csv"、System.Text.Encoding.UTF8)
neuro5torm

1
CSVのフィールドに空白行が含まれている場合、によってスキップされることに注意してくださいTextFieldParser.ReadLine()TextFieldParserのドキュメントを
mcNux

3
.NET Coreでこれを取得する方法はありますか?
Hugo Zink

183

CsvHelper(私が管理するライブラリ)は、CSVファイルをカスタムオブジェクトに読み込みます。

var csv = new CsvReader( File.OpenText( "file.csv" ) );
var myCustomObjects = csv.GetRecords<MyCustomObject>();

読み込もうとしているオブジェクトを所有していない場合があります。この場合、クラスに属性を配置できないため、流れるようなマッピングを使用できます。

public sealed class MyCustomObjectMap : CsvClassMap<MyCustomObject>
{
    public MyCustomObjectMap()
    {
        Map( m => m.Property1 ).Name( "Column Name" );
        Map( m => m.Property2 ).Index( 4 );
        Map( m => m.Property3 ).Ignore();
        Map( m => m.Property4 ).TypeConverter<MySpecialTypeConverter>();
    }
}

編集:

CsvReaderでは、CultureInfoをコンストラクターに渡す必要がありますhttps://github.com/JoshClose/CsvHelper/issues/1441)。

例:

var csv = new CsvReader(File.OpenText("file.csv"), System.Globalization.CultureInfo.CurrentCulture);

18
@ kubal5003に同意します。それで私を売ったのは、あなたがそれをNuGetパッケージとして利用できることでした。おかげで、それは高速で、必要なすべてのcsv読み取りを実行します。
Gromer、2012

7
それはすごく速いです。130万件のレコードが10秒で読み取られ、逆シリアル化されました。
マリスク

2
実装が非常に簡単な素晴らしいライブラリ。この回答が作成されてからライブラリが少し変更され、CsvHelperをインスタンス化できなくなったため(現在は名前空間のみです)、CsvReaderクラスを使用する必要があるため、Joshにここで彼の回答を更新することをお勧めします。
Marko 2013

1
CsvClassMapはCsvHelperの最新バージョンに存在しないようですか?
knocte

1
knocte、それは現在ClassMapと呼ばれています。ヘッダーレコードを要求する前に読み取りを行う必要があるなど、他の変更もあります(これは、最初のRead()呼び出しで読み取られたものに設定されます)。他の人が以前に述べたように、それは超高速で扱いやすいです。
Norgie、2017年

31

ビジネスアプリケーションでは、codeproject.comのオープンソースプロジェクトCSVReaderを使用します。

それはうまく機能し、優れたパフォーマンスを発揮します。私が提供したリンクにはいくつかのベンチマークがあります。

プロジェクトページからコピーした簡単な例:

using (CsvReader csv = new CsvReader(new StreamReader("data.csv"), true))
{
    int fieldCount = csv.FieldCount;
    string[] headers = csv.GetFieldHeaders();

    while (csv.ReadNextRecord())
    {
        for (int i = 0; i < fieldCount; i++)
            Console.Write(string.Format("{0} = {1};", headers[i], csv[i]));

        Console.WriteLine();
    }
}

ご覧のとおり、操作は非常に簡単です。



12

csvファイルの読み取りのみが必要な場合は、次のライブラリをお勧めします:高速CSVリーダー
csvファイルを生成する必要がある場合は、次のライブラリを使用します:FileHelpers

どちらも無料でオープンソースです。


FileHelpersには魅力的な要約があります:filehelpers.com FileHelpersは無料で使いやすい.NETライブラリで、ファイル、文字列、またはストリーム内の固定長または区切られたレコードからデータをインポート/エクスポートできます。
AnneTheAgile 2012年

このリンクは質問に回答する可能性がありますが、スタックオーバーフローではリンクのみの回答は推奨されませんが、リンクの重要な部分を取り、それを回答に入れることにより、この回答を改善できます。これにより、リンクが変更された場合でも回答が回答になります。または削除されました:)
WhatsThePoint

11

これが私が頻繁に使用するヘルパークラスです。誰かがこのスレッドに戻ってきた場合に備えて(共有したかったのですが)。

これは、すぐに使用できるプロジェクトに簡単に移植できるようにするために使用します。

public class CSVHelper : List<string[]>
{
  protected string csv = string.Empty;
  protected string separator = ",";

  public CSVHelper(string csv, string separator = "\",\"")
  {
    this.csv = csv;
    this.separator = separator;

    foreach (string line in Regex.Split(csv, System.Environment.NewLine).ToList().Where(s => !string.IsNullOrEmpty(s)))
    {
      string[] values = Regex.Split(line, separator);

      for (int i = 0; i < values.Length; i++)
      {
        //Trim values
        values[i] = values[i].Trim('\"');
      }

      this.Add(values);
    }
  }
}

そしてそれを次のように使用します:

public List<Person> GetPeople(string csvContent)
{
  List<Person> people = new List<Person>();
  CSVHelper csv = new CSVHelper(csvContent);
  foreach(string[] line in csv)
  {
    Person person = new Person();
    person.Name = line[0];
    person.TelephoneNo = line[1];
    people.Add(person);
  }
  return people;
}

[更新されたcsvヘルパー:最後の改行文字が新しい行を作成するバグが修正されました]


17
csvエントリのいずれかにコンマ(、)が含まれている場合、このコードは機能しません。
ハカン

物事を軽量に保つために、区切り文字としてパイプ文字を使用しました。'|'
Base33

優れたソリューション。2番目のスニペットに関する質問です。Personはどのタイプのオブジェクトですか
Cocoa Dev 2013年

@CocoaDevこれは、NameとTelephoneNoの2つの文字列プロパティを含むクラスです。純粋に例として。プロパティのいずれかが整数の場合、それは単純な変換(チェックあり)である必要があります。
Base33、2013年

10

このソリューションは、公式のMicrosoft.VisualBasicアセンブリを使用してCSVを解析しています。

利点:

  • 区切り文字のエスケープ
  • ヘッダーを無視
  • スペースをトリムする
  • コメントを無視する

コード:

    using Microsoft.VisualBasic.FileIO;

    public static List<List<string>> ParseCSV (string csv)
    {
        List<List<string>> result = new List<List<string>>();


        // To use the TextFieldParser a reference to the Microsoft.VisualBasic assembly has to be added to the project. 
        using (TextFieldParser parser = new TextFieldParser(new StringReader(csv))) 
        {
            parser.CommentTokens = new string[] { "#" };
            parser.SetDelimiters(new string[] { ";" });
            parser.HasFieldsEnclosedInQuotes = true;

            // Skip over header line.
            //parser.ReadLine();

            while (!parser.EndOfData)
            {
                var values = new List<string>();

                var readFields = parser.ReadFields();
                if (readFields != null)
                    values.AddRange(readFields);
                result.Add(values);
            }
        }

        return result;
    }

7

TinyCsvParserを書きました周りの最速の.NETパーサの1とほぼすべてのCSVフォーマットを解析する高度な設定が可能です.NETのために。

それはMITライセンスの下でリリースされています:

NuGetを使用してインストールできます。パッケージマネージャーコンソールで次のコマンドを実行します。

PM> Install-Package TinyCsvParser

使用法

persons.csv氏名、生年月日が記載された人物のリストがCSVファイルにあるとします。

FirstName;LastName;BirthDate
Philipp;Wagner;1986/05/12
Max;Musterman;2014/01/02

システムの対応するドメインモデルは次のようになります。

private class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }
}

TinyCsvParserを使用する場合、CSVデータの列とドメインモデルのプロパティの間のマッピングを定義する必要があります。

private class CsvPersonMapping : CsvMapping<Person>
{

    public CsvPersonMapping()
        : base()
    {
        MapProperty(0, x => x.FirstName);
        MapProperty(1, x => x.LastName);
        MapProperty(2, x => x.BirthDate);
    }
}

次に、マッピングを使用して、CSVデータをで解析できますCsvParser

namespace TinyCsvParser.Test
{
    [TestFixture]
    public class TinyCsvParserTest
    {
        [Test]
        public void TinyCsvTest()
        {
            CsvParserOptions csvParserOptions = new CsvParserOptions(true, new[] { ';' });
            CsvPersonMapping csvMapper = new CsvPersonMapping();
            CsvParser<Person> csvParser = new CsvParser<Person>(csvParserOptions, csvMapper);

            var result = csvParser
                .ReadFromFile(@"persons.csv", Encoding.ASCII)
                .ToList();

            Assert.AreEqual(2, result.Count);

            Assert.IsTrue(result.All(x => x.IsValid));

            Assert.AreEqual("Philipp", result[0].Result.FirstName);
            Assert.AreEqual("Wagner", result[0].Result.LastName);

            Assert.AreEqual(1986, result[0].Result.BirthDate.Year);
            Assert.AreEqual(5, result[0].Result.BirthDate.Month);
            Assert.AreEqual(12, result[0].Result.BirthDate.Day);

            Assert.AreEqual("Max", result[1].Result.FirstName);
            Assert.AreEqual("Mustermann", result[1].Result.LastName);

            Assert.AreEqual(2014, result[1].Result.BirthDate.Year);
            Assert.AreEqual(1, result[1].Result.BirthDate.Month);
            Assert.AreEqual(1, result[1].Result.BirthDate.Day);
        }
    }
}

ユーザーガイド

完全なユーザーガイドは次の場所にあります。


1

これが私のKISS実装です...

using System;
using System.Collections.Generic;
using System.Text;

class CsvParser
{
    public static List<string> Parse(string line)
    {
        const char escapeChar = '"';
        const char splitChar = ',';
        bool inEscape = false;
        bool priorEscape = false;

        List<string> result = new List<string>();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < line.Length; i++)
        {
            char c = line[i];
            switch (c)
            {
                case escapeChar:
                    if (!inEscape)
                        inEscape = true;
                    else
                    {
                        if (!priorEscape)
                        {
                            if (i + 1 < line.Length && line[i + 1] == escapeChar)
                                priorEscape = true;
                            else
                                inEscape = false;
                        }
                        else
                        {
                            sb.Append(c);
                            priorEscape = false;
                        }
                    }
                    break;
                case splitChar:
                    if (inEscape) //if in escape
                        sb.Append(c);
                    else
                    {
                        result.Add(sb.ToString());
                        sb.Length = 0;
                    }
                    break;
                default:
                    sb.Append(c);
                    break;
            }
        }

        if (sb.Length > 0)
            result.Add(sb.ToString());

        return result;
    }

}

1
これは、CSVファイルで有効な引用符付き文字列内の改行を扱いません。
ジョンライデグレン2018年

アレックス、ジョンが言っていることは、RFC 4180(ietf.org/rfc/rfc4180.txt-セクション2とアイテム6を参照)により、列の中央にCR LFを設定して、効果的に広げることができるということです。ファイルの2行。ソリューションはおそらくほとんどの場合(特にCSVファイルがExcelからの保存によって作成された場合)でうまく機能しますが、このエッジケースはカバーしていません。上記のCsvHelperは、このケースを考慮に入れるべきです。
David Yates

はい、これは本当ですが、CSVにCR LFがある場合、おそらくCSVを使用すべきではなく、json、xml、または固定長形式など、より適切なものを使用する必要があります。
Alex Begun 2018年

1

少し前に、Microsoft.VisualBasicライブラリに基づいてCSV読み取り/書き込み用の単純なクラスを作成しました。この単純なクラスを使用すると、2次元配列のようにCSVを操作できます。次のリンクで私のクラスを見つけることができます:https : //github.com/ukushu/DataExporter

簡単な使用例:

Csv csv = new Csv("\t");//delimiter symbol

csv.FileOpen("c:\\file1.csv");

var row1Cell6Value = csv.Rows[0][5];

csv.AddRow("asdf","asdffffff","5")

csv.FileSave("c:\\file2.csv");

ヘッダーを読み取るために必要なのはcsv.Rows[0]セルを読み取ることだけです:)


1

簡単な解析のニーズに対応する単一のソースファイルソリューション。すべての厄介なエッジケースを処理します。改行の正規化や引用符付き文字列リテラルでの改行の処理など。どういたしまして!

CSVファイルにヘッダーがある場合は、最初の行から列名(および列インデックスの計算)を読み取るだけです。そのような単純な。

これDumpはLINQPadメソッドであることに注意してください。LINQPadを使用していない場合は、これを削除することをお勧めします。

void Main()
{
    var file1 = "a,b,c\r\nx,y,z";
    CSV.ParseText(file1).Dump();

    var file2 = "a,\"b\",c\r\nx,\"y,z\"";
    CSV.ParseText(file2).Dump();

    var file3 = "a,\"b\",c\r\nx,\"y\r\nz\"";
    CSV.ParseText(file3).Dump();

    var file4 = "\"\"\"\"";
    CSV.ParseText(file4).Dump();
}

static class CSV
{
    public struct Record
    {
        public readonly string[] Row;

        public string this[int index] => Row[index];

        public Record(string[] row)
        {
            Row = row;
        }
    }

    public static List<Record> ParseText(string text)
    {
        return Parse(new StringReader(text));
    }

    public static List<Record> ParseFile(string fn)
    {
        using (var reader = File.OpenText(fn))
        {
            return Parse(reader);
        }
    }

    public static List<Record> Parse(TextReader reader)
    {
        var data = new List<Record>();

        var col = new StringBuilder();
        var row = new List<string>();
        for (; ; )
        {
            var ln = reader.ReadLine();
            if (ln == null) break;
            if (Tokenize(ln, col, row))
            {
                data.Add(new Record(row.ToArray()));
                row.Clear();
            }
        }

        return data;
    }

    public static bool Tokenize(string s, StringBuilder col, List<string> row)
    {
        int i = 0;

        if (col.Length > 0)
        {
            col.AppendLine(); // continuation

            if (!TokenizeQuote(s, ref i, col, row))
            {
                return false;
            }
        }

        while (i < s.Length)
        {
            var ch = s[i];
            if (ch == ',')
            {
                row.Add(col.ToString().Trim());
                col.Length = 0;
                i++;
            }
            else if (ch == '"')
            {
                i++;
                if (!TokenizeQuote(s, ref i, col, row))
                {
                    return false;
                }
            }
            else
            {
                col.Append(ch);
                i++;
            }
        }

        if (col.Length > 0)
        {
            row.Add(col.ToString().Trim());
            col.Length = 0;
        }

        return true;
    }

    public static bool TokenizeQuote(string s, ref int i, StringBuilder col, List<string> row)
    {
        while (i < s.Length)
        {
            var ch = s[i];
            if (ch == '"')
            {
                // escape sequence
                if (i + 1 < s.Length && s[i + 1] == '"')
                {
                    col.Append('"');
                    i++;
                    i++;
                    continue;
                }
                i++;
                return true;
            }
            else
            {
                col.Append(ch);
                i++;
            }
        }
        return false;
    }
}

1

このリストのもう1つ、Cinchoo ETL-複数のファイル形式(CSV、フラットファイル、Xml、JSONなど)を読み書きするためのオープンソースライブラリ

以下のサンプルは、CSVファイルをすばやく読み取る方法を示しています(POCOオブジェクトは不要)

string csv = @"Id, Name
1, Carl
2, Tom
3, Mark";

using (var p = ChoCSVReader.LoadText(csv)
    .WithFirstLineHeader()
    )
{
    foreach (var rec in p)
    {
        Console.WriteLine($"Id: {rec.Id}");
        Console.WriteLine($"Name: {rec.Name}");
    }
}

以下のサンプルは、POCOオブジェクトを使用してCSVファイルを読み取る方法を示しています

public partial class EmployeeRec
{
    public int Id { get; set; }
    public string Name { get; set; }
}

static void CSVTest()
{
    string csv = @"Id, Name
1, Carl
2, Tom
3, Mark";

    using (var p = ChoCSVReader<EmployeeRec>.LoadText(csv)
        .WithFirstLineHeader()
        )
    {
        foreach (var rec in p)
        {
            Console.WriteLine($"Id: {rec.Id}");
            Console.WriteLine($"Name: {rec.Name}");
        }
    }
}

使い方はCodeProjectの記事をご覧ください。


0

C#split()関数を使用してCSVを適切に分割する方法に関する無制限の投稿に基づいていますか?

string[] tokens = System.Text.RegularExpressions.Regex.Split(paramString, ",");

注:これは、エスケープ/ネストされたカンマなどを処理しないため、特定の単純なCSVリストにのみ適しています。


2
これは非常に悪く、おそらく遅い:)
EKS

1
おそらく、しかしそれは完全にそして単純に少数のパラメーターのセットに対して機能するので、有効で役立つ解決策です。なぜ反対票を投じるのですか?「とても悪い」はちょっと極端ですね。
radsdau 2016

1
エスケープ/ネストされたカンマなどは処理しません。場合によっては機能しますが、すべてのcsvファイルに対しては機能しません
NStuke

あなたは正しいです。それを反映するように返信を編集します。ありがとう。しかし、それはまだその場所を持っています。
radsdau

これは、SQLサーバーclr dllを構築していて、これらの他の外部パッケージを使用できない私のユースケースでは完全に機能しました。ファイル名と行数を含む単純なcsvファイルを解析する必要があるだけです。
dubvfan87

0

このコードはcsvをDataTableに読み取ります。

public static DataTable ReadCsv(string path)
{
    DataTable result = new DataTable("SomeData");
    using (TextFieldParser parser = new TextFieldParser(path))
    {
        parser.TextFieldType = FieldType.Delimited;
        parser.SetDelimiters(",");
        bool isFirstRow = true;
        //IList<string> headers = new List<string>();

        while (!parser.EndOfData)
        {
            string[] fields = parser.ReadFields();
            if (isFirstRow)
            {
                foreach (string field in fields)
                {
                    result.Columns.Add(new DataColumn(field, typeof(string)));
                }
                isFirstRow = false;
            }
            else
            {
                int i = 0;
                DataRow row = result.NewRow();
                foreach (string field in fields)
                {
                    row[i++] = field;
                }
                result.Rows.Add(row);
            }
        }
    }
    return result;
}

1
TextFieldParserはMicrosoft.VisualBasic.dllにあります。
user3285954

0

だれかがスニペットを必要とする場合、ライブラリをバインドしたり、パッケージをダウンロードしたりすることなく、コードに組み込むことができます。ここに私が書いたバージョンがあります:

    public static string FormatCSV(List<string> parts)
    {
        string result = "";

        foreach (string s in parts)
        {
            if (result.Length > 0)
            {
                result += ",";

                if (s.Length == 0)
                    continue;
            }

            if (s.Length > 0)
            {
                result += "\"" + s.Replace("\"", "\"\"") + "\"";
            }
            else
            {
                // cannot output double quotes since its considered an escape for a quote
                result += ",";
            }
        }

        return result;
    }

    enum CSVMode
    {
        CLOSED = 0,
        OPENED_RAW = 1,
        OPENED_QUOTE = 2
    }

    public static List<string> ParseCSV(string input)
    {
        List<string> results;

        CSVMode mode;

        char[] letters;

        string content;


        mode = CSVMode.CLOSED;

        content = "";
        results = new List<string>();
        letters = input.ToCharArray();

        for (int i = 0; i < letters.Length; i++)
        {
            char letter = letters[i];
            char nextLetter = '\0';

            if (i < letters.Length - 1)
                nextLetter = letters[i + 1];

            // If its a quote character
            if (letter == '"')
            {
                // If that next letter is a quote
                if (nextLetter == '"' && mode == CSVMode.OPENED_QUOTE)
                {
                    // Then this quote is escaped and should be added to the content

                    content += letter;

                    // Skip the escape character
                    i++;
                    continue;
                }
                else
                {
                    // otherwise its not an escaped quote and is an opening or closing one
                    // Character is skipped

                    // If it was open, then close it
                    if (mode == CSVMode.OPENED_QUOTE)
                    {
                        results.Add(content);

                        // reset the content
                        content = "";

                        mode = CSVMode.CLOSED;

                        // If there is a next letter available
                        if (nextLetter != '\0')
                        {
                            // If it is a comma
                            if (nextLetter == ',')
                            {
                                i++;
                                continue;
                            }
                            else
                            {
                                throw new Exception("Expected comma. Found: " + nextLetter);
                            }
                        }
                    }
                    else if (mode == CSVMode.OPENED_RAW)
                    {
                        // If it was opened raw, then just add the quote 
                        content += letter;
                    }
                    else if (mode == CSVMode.CLOSED)
                    {
                        // Otherwise open it as a quote 

                        mode = CSVMode.OPENED_QUOTE;
                    }
                }
            }
            // If its a comma seperator
            else if (letter == ',')
            {
                // If in quote mode
                if (mode == CSVMode.OPENED_QUOTE)
                {
                    // Just read it
                    content += letter;
                }
                // If raw, then close the content
                else if (mode == CSVMode.OPENED_RAW)
                {
                    results.Add(content);

                    content = "";

                    mode = CSVMode.CLOSED;
                }
                // If it was closed, then open it raw
                else if (mode == CSVMode.CLOSED)
                {
                    mode = CSVMode.OPENED_RAW;

                    results.Add(content);

                    content = "";
                }
            }
            else
            {
                // If opened quote, just read it
                if (mode == CSVMode.OPENED_QUOTE)
                {
                    content += letter;
                }
                // If opened raw, then read it
                else if (mode == CSVMode.OPENED_RAW)
                {
                    content += letter;
                }
                // It closed, then open raw
                else if (mode == CSVMode.CLOSED)
                {
                    mode = CSVMode.OPENED_RAW;

                    content += letter;
                }
            }
        }

        // If it was still reading when the buffer finished
        if (mode != CSVMode.CLOSED)
        {
            results.Add(content);
        }

        return results;
    }

0

これは短くて簡単な解決策です。

                using (TextFieldParser parser = new TextFieldParser(outputLocation))
                 {
                        parser.TextFieldType = FieldType.Delimited;
                        parser.SetDelimiters(",");
                        string[] headers = parser.ReadLine().Split(',');
                        foreach (string header in headers)
                        {
                            dataTable.Columns.Add(header);
                        }
                        while (!parser.EndOfData)
                        {
                            string[] fields = parser.ReadFields();
                            dataTable.Rows.Add(fields);
                        }
                    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.