Parsing CSV files in C#, with header

后端 未结 17 1536
悲哀的现实
悲哀的现实 2020-11-21 06:57

Is there a default/official/recommended way to parse CSV files in C#? I don\'t want to roll my own parser.

Also, I\'ve seen instances of people using ODBC/OLE DB to

相关标签:
17条回答
  • 2020-11-21 06:59

    Here is a helper class I use often, in case any one ever comes back to this thread (I wanted to share it).

    I use this for the simplicity of porting it into projects ready to use:

    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);
        }
      }
    }
    

    And use it like:

    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;
    }
    

    [Updated csv helper: bug fixed where the last new line character created a new line]

    0 讨论(0)
  • 2020-11-21 07:04

    This solution is using the official Microsoft.VisualBasic assembly to parse CSV.

    Advantages:

    • delimiter escaping
    • ignores Header
    • trim spaces
    • ignore comments

    Code:

        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;
        }
    
    0 讨论(0)
  • 2020-11-21 07:07

    I know its a bit late but just found a library Microsoft.VisualBasic.FileIO which has TextFieldParser class to process csv files.

    0 讨论(0)
  • Based on unlimit's post on How to properly split a CSV using C# split() function? :

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

    NOTE: this doesn't handle escaped / nested commas, etc., and therefore is only suitable for certain simple CSV lists.

    0 讨论(0)
  • 2020-11-21 07:13

    Here is my KISS implementation...

    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;
        }
    
    }
    
    0 讨论(0)
  • 2020-11-21 07:14

    CsvHelper (a library I maintain) will read a CSV file into custom objects.

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

    Sometimes you don't own the objects you're trying to read into. In this case, you can use fluent mapping because you can't put attributes on the class.

    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>();
        }
    }
    

    EDIT:

    CsvReader now requires CultureInfo to be passed into the constuctor (https://github.com/JoshClose/CsvHelper/issues/1441).

    Example:

    var csv = new CsvReader(File.OpenText("file.csv"), System.Globalization.CultureInfo.CurrentCulture);
    
    0 讨论(0)
提交回复
热议问题