แยกไฟล์ CSV ใน C # ด้วยส่วนหัว


266

มีวิธีเริ่มต้น / เป็นทางการ / แนะนำในการแยกวิเคราะห์ไฟล์ CSV ใน C # หรือไม่ ฉันไม่ต้องการที่จะม้วน parser ของฉันเอง

นอกจากนี้ฉันได้เห็นอินสแตนซ์ของผู้ใช้ ODBC / OLE DB เพื่ออ่าน CSV ผ่านทางไดรเวอร์ข้อความและผู้คนจำนวนมากไม่สนับสนุนสิ่งนี้เนื่องจาก "ข้อเสีย" ข้อเสียเหล่านี้คืออะไร?

เป็นการดีที่ฉันกำลังมองหาวิธีที่ฉันสามารถอ่าน CSV โดยชื่อคอลัมน์โดยใช้ระเบียนแรกเป็นชื่อส่วนหัว / ฟิลด์ คำตอบบางคำตอบที่ให้นั้นถูกต้อง แต่โดยทั่วไปแล้วทำการ deserialize ไฟล์เป็นคลาส

คำตอบ:


138

ให้ห้องสมุดจัดการกับรายละเอียดที่เป็นประโยชน์สำหรับคุณ! :-)

ตรวจสอบFileHelpersและอยู่แห้ง - อย่าทำซ้ำตัวเอง - ไม่จำเป็นต้องคิดค้นวงล้อใหม่เป็นครั้งที่หนึ่งพันล้าน ...

โดยทั่วไปคุณเพียงแค่ต้องกำหนดรูปร่างของข้อมูลของคุณ - เขตข้อมูลในแต่ละบรรทัดของคุณใน CSV - โดยใช้คลาสสาธารณะ (และแอตทริบิวต์ที่คิดออกมาดีเช่นค่าเริ่มต้นการแทนที่ค่า NULL เป็นต้น) เอ็นจิน FileHelpers ที่ไฟล์และ bingo - คุณจะได้รับข้อมูลทั้งหมดคืนจากไฟล์นั้น ใช้งานง่ายอย่างเดียว - ประสิทธิภาพที่ยอดเยี่ยม!


1
จนกว่าคุณจะต้องการ sth จริง ๆ (และส่วนใหญ่ที่สามารถนำมาใช้เป็นส่วนขยายต่อไป) FileHelpers เป็นวิธีที่ดีที่สุดที่จะไปสะดวกจริงๆผ่านการทดสอบและการแก้ปัญหาที่ดี
mikus

3
ตั้งแต่วันที่ 1 มิถุนายน 2558 วิธีเดียวที่ฉันสามารถดาวน์โหลด FileHelpers ได้คือการค้นหาบน sourceforge.net นี่คือลิงค์ที่ใช้: sourceforge.net/projects/filehelpers/?source=directory
Sudhanshu Mishra

2
@dotnetguy เรากำลังจะปล่อย 3.1 (ปัจจุบัน 3.1-rc2) ออกมาแล้ว นอกจากนี้เราได้ออกแบบเว็บไซต์ใหม่อีกครั้ง: www.filehelpers.net คุณสามารถดาวน์โหลดเวอร์ชั่นล่าสุดได้จากที่นั่น
Marcos Meli

1
@MarcosMeli ขอบคุณมาก! ฉันใช้ FileHelpers ในโครงการของฉันไปแล้วและมันก็เป็นเรื่องง่ายที่จะใช้ - ความรุ่งโรจน์ของทีม ฉันกำลังวางแผนบล็อกไว้ในไม่ช้าและ btw - รักเว็บไซต์ใหม่ - ทำได้ดีมาก!
Sudhanshu Mishra

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 Class

PS หากคุณต้องการผู้ส่งออก CSV ลองCsvExport (เปิดเผย: ฉันเป็นหนึ่งในผู้ร่วมให้ข้อมูล)


2
จากประสบการณ์ของฉัน TextFieldParser ทำงานได้ไม่ดีกับไฟล์ขนาดใหญ่ (เช่น> 250Mb) :(
MBoros

6
TextFieldParser ใช้ IDisposable ดังนั้นอาจเป็นการดีที่สุดที่จะใช้ในประโยคการใช้ คำตอบที่ดีเป็นอย่างอื่น
Chris Bush

3
ใน Constructor คุณอาจต้องการใช้การเข้ารหัสที่แตกต่างจากที่เป็นค่าเริ่มต้นเช่น: TextFieldParser ใหม่ ("c: \ temp \ test.csv", System.Text.Encoding.UTF8)
neural5torm

1
โปรดทราบว่าถ้ามีข้อมูลในรูปแบบ CSV TextFieldParser.ReadLine()ของคุณมีบรรทัดว่างพวกเขาจะข้ามโดย ดูTextFieldParser docs
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 ไปยัง constuctor ( https://github.com/JoshClose/CsvHelper/issues/1441 )

ตัวอย่าง:

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

18
ฉันเห็นด้วยกับ @ kubal5003 สิ่งที่ขายให้ฉันเมื่อคุณมีมันเป็นแพคเกจ NuGet ขอบคุณผู้ชายมันเร็วและอ่าน csv ทั้งหมดที่ฉันต้องการ
Gromer

7
มันเร็วมาก 1.3 ล้านบันทึกการอ่านและ deserialized ใน 10 วินาที
marisks

2
ห้องสมุดที่ยอดเยี่ยมใช้งานง่ายมาก ฉันอยากจะแนะนำ Josh ให้อัปเดตคำตอบของเขาที่นี่เพราะห้องสมุดเปลี่ยนไปเล็กน้อยตั้งแต่คำตอบนี้ถูกเขียนขึ้นและคุณไม่สามารถยกตัวอย่าง CsvHelper ได้อีกต่อไป (ตอนนี้เป็นเพียง namespace เท่านั้น) แต่คุณต้องใช้คลาส CsvReader
Marko

1
ดูเหมือนว่า CsvClassMap จะไม่มีอยู่ใน CsvHelper รุ่นล่าสุดใช่หรือไม่
knocte

1
ถ้าอย่างนั้นก็เรียกว่า ClassMap ในขณะนี้ นอกจากนี้ยังมีการเปลี่ยนแปลงอื่น ๆ เช่นการอ่านก่อนถามเร็กคอร์ดส่วนหัว (ซึ่งวิธีการได้รับการตั้งค่าเป็นสิ่งที่ถูกอ่านโดยการโทรครั้งแรกเพื่ออ่าน ()) เหมือนอย่างที่คนอื่น ๆ พูดถึงมาก่อนมันเร็วและง่ายต่อการทำงานด้วย
norgie

31

ในการประยุกต์ทางธุรกิจที่ใช้ i โครงการที่มาเปิดใน 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

ในขณะที่ลิงก์นี้อาจตอบคำถาม แต่ลิงก์เพียงคำตอบนั้นไม่ได้รับการสนับสนุนใน Stack Overflow คุณสามารถปรับปรุงคำตอบนี้ได้โดยนำส่วนสำคัญของลิงก์และใส่ลงในคำตอบของคุณทำให้แน่ใจว่าคำตอบของคุณยังคงเป็นคำตอบ หรือลบ :)
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 ใด ๆ มีเครื่องหมายจุลภาค (,) รหัสนี้จะไม่ทำงาน
hakan

เพื่อให้สิ่งต่าง ๆ มีน้ำหนักเบาฉันใช้ตัวอักษรไพพ์เป็นตัวคั่น '|'
Base33

ทางออกที่ดีเยี่ยม แค่คำถามเกี่ยวกับตัวอย่างที่สอง ประเภทของวัตถุคือ Person
Cocoa Dev

@CocoaDev มันเป็นคลาสที่มีคุณสมบัติสตริงสอง - ชื่อและ TelephoneNo อย่างหมดจดสำหรับตัวอย่างแม้ว่า หากคุณสมบัติใด ๆ เป็นจำนวนเต็มควรเป็นเพียงการแปลงไปข้างหน้าแบบตรง (พร้อมกาหรือไม่)
Base33

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 ซึ่งเป็นหนึ่งในตัวแยกวิเคราะห์. NET ที่เร็วที่สุดและตั้งค่าได้อย่างสูงในการแยกวิเคราะห์เกือบทุกรูปแบบ CSV

เผยแพร่ภายใต้ลิขสิทธิ์ของ MIT:

คุณสามารถใช้NuGetเพื่อติดตั้ง เรียกใช้คำสั่งต่อไปนี้ในคอนโซลการจัดการแพคเกจ

PM> Install-Package TinyCsvParser

การใช้

ลองนึกภาพเรามีรายชื่อบุคคลในไฟล์ CSV ที่persons.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
John Leidegren

อเล็กซ์สิ่งที่จอห์นพยายามจะพูดก็คือ RFC 4180 ( ietf.org/rfc/rfc4180.txt - ดูหัวข้อที่ 2 และรายการที่ 6) อนุญาตให้คอลัมน์มี CR LF ตรงกลางคอลัมน์ได้อย่างมีประสิทธิภาพ 2 บรรทัดในไฟล์ โซลูชันของคุณอาจทำงานได้ดีในกรณีส่วนใหญ่ (โดยเฉพาะอย่างยิ่งหากไฟล์ CSV ถูกสร้างขึ้นโดยการบันทึกออกจาก Excel) แต่ไม่ครอบคลุมกรณีขอบนี้ CsvHelper ที่กล่าวถึงข้างต้นควรพิจารณากรณีนี้
เดวิดเยตส์

ใช่นี่เป็นความจริง แต่ถ้าคุณมี CR LF ใน CSV โอกาสที่คุณไม่ควรใช้ CSV แต่มีรูปแบบที่เหมาะสมกว่าเช่น json หรือ xml หรือความยาวคงที่
อเล็กซ์เริ่ม

1

บางครั้งก่อนหน้านี้ฉันได้เขียนคลาสง่าย ๆ สำหรับการอ่าน / เขียน CSV ตามMicrosoft.VisualBasicไลบรารี เมื่อใช้คลาสแบบง่ายนี้คุณจะสามารถทำงานกับ CSV เช่นเดียวกับอาร์เรย์ 2 มิติ คุณสามารถหาชั้นเรียนของฉันได้จากลิงค์ต่อไปนี้: 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

อีกหนึ่งในรายการนี้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}");
    }
}

ตัวอย่างด้านล่างแสดงวิธีอ่านไฟล์ CSV โดยใช้ออบเจ็กต์ POCO

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

จากการโพสต์ไม่ จำกัด ของวิธีการแบ่ง CSV อย่างถูกต้องโดยใช้ฟังก์ชัน C # split ()? :

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

หมายเหตุ: สิ่งนี้ไม่ได้จัดการกับเครื่องหมายจุลภาคที่ใช้ Escape / ซ้อนกันและดังนั้นจึงเหมาะสำหรับรายการ CSV ที่เรียบง่ายเท่านั้น


2
นี่แย่มากและช้ามาก :)
EKS

1
อาจเป็นไปได้ แต่มันทำงานได้อย่างสมบูรณ์และเรียบง่ายสำหรับชุดพารามิเตอร์ขนาดเล็กดังนั้นจึงเป็นวิธีการแก้ไขที่ถูกต้อง ลงคะแนนทำไม "แย่มาก" น้อยไปหน่อยคุณไม่คิดเหรอ?
radsdau

1
มันไม่สามารถจัดการกับคอมมา /
คอมม่าที่

คุณพูดถูก ฉันจะแก้ไขคำตอบเพื่อให้สะท้อนถึงสิ่งนั้น ขอบคุณ แต่มันก็ยังมีที่อยู่
radsdau

สิ่งนี้ทำงานได้อย่างสมบูรณ์แบบสำหรับกรณีการใช้งานของฉันที่ฉันสร้าง sql server 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.