Разбор CSV-файлов в C #, с заголовком - PullRequest
229 голосов
/ 17 января 2010

Есть ли по умолчанию / официальный / рекомендуемый способ анализа файлов CSV в C #? Я не хочу закатывать свой собственный парсер.

Кроме того, я видел случаи, когда люди использовали ODBC / OLE DB для чтения CSV через текстовый драйвер, и многие люди препятствовали этому из-за его «недостатков». Каковы эти недостатки?

В идеале я ищу способ, с помощью которого я могу прочитать CSV по имени столбца, используя первую запись в качестве имени заголовка / поля. Некоторые из приведенных ответов верны, но в основном они десериализуют файл в классы.

Ответы [ 16 ]

309 голосов
/ 11 декабря 2013

Анализатор 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 (диск: я одинучастников)

167 голосов
/ 31 января 2012

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>();
    }
}
124 голосов
/ 17 января 2010

Пусть библиотека обработает все мелкие детали для вас! : -)

Проверьте FileHelpers и оставайтесь сухими - не повторяйте себя - не нужно изобретать велосипед в миллиардный раз ....

Вам просто нужно определить эту форму ваших данных - полей в отдельной строке в CSV - с помощью открытого класса (и таких хорошо продуманных атрибутов, как значения по умолчанию, замены для значений NULL и т. Д. ), наведите движок FileHelpers на файл, а на бинго - вы получите все записи из этого файла. Одна простая операция - отличная производительность!

31 голосов
/ 17 января 2010

В бизнес-приложении я использую проект с открытым исходным кодом на 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();
    }
}

Как видите, с ним очень легко работать.

17 голосов
/ 21 мая 2012

Я знаю, что немного поздно, но только что нашел библиотеку Microsoft.VisualBasic.FileIO, в которой есть класс TextFieldParser для обработки CSV-файлов.

12 голосов
/ 17 января 2010

Если вам нужно только чтение CSV-файлов, я рекомендую эту библиотеку: Быстрое CSV-ридер
Если вам также нужно сгенерировать CSV-файлы, используйте этот: FileHelpers

Они оба бесплатны и имеют открытый исходный код.

10 голосов
/ 30 марта 2012

Вот вспомогательный класс, которым я часто пользуюсь, на случай, если кто-нибудь когда-нибудь вернется в этот поток (я хотел поделиться им).

Я использую это для простоты переноса его на проекты, готовые к использованию:

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: исправлена ​​ошибка, из-за которой последний символ новой строки создавал новую строку]

8 голосов
/ 27 июля 2016

Это решение использует официальную 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 голосов
/ 13 января 2016

Я написал 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);
        }
    }
}

Руководство пользователя

Полное руководство пользователя доступно по адресу:

3 голосов
/ 17 января 2010

Официального пути я не знаю, но вы действительно должны использовать существующие библиотеки.Вот что я нашел очень полезным из CodeProject:

http://www.codeproject.com/KB/database/CsvReader.aspx

...