Чтение файлов CSV в [закрытом] C#

Реклама Кислородный редактор XML имеет функцию профилирования и отладки файлов XSLT. Это - хороший XML-редактор, также.

13
задан George Stocker 9 October 2009 в 16:13
поделиться

4 ответа

Взгляните на A Fast CSV Reader на CodeProject.

23
ответ дан 1 December 2019 в 17:11
поделиться

Здесь написано с уважением, чтобы использовать общие коллекции и блоки итераторов. Он поддерживает текстовые поля, заключенные в двойные кавычки (в том числе те, которые охватывают несколько строк) с использованием соглашения о двойном экранировании (так "" внутри поля в кавычках читается как символ одинарной кавычки). Он не поддерживает:

  • Текст, заключенный в одинарные кавычки
  • \ -экранированный текст в кавычках
  • альтернативные разделители (пока не работают с полями, разделенными вертикальной чертой или табуляцией)
  • Текстовые поля без кавычек, начинающиеся с кавычек

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

Сейчас на GitHub

Обновление : казалось, что добавить поддержку заключенного текста в одинарные кавычки. Это простое изменение, но я ввел его прямо в окно ответа, поэтому оно не проверялось. Используйте ссылку на версию внизу, если вы предпочитаете старый (проверенный) код.

public static class CSV
{
    public static IEnumerable<IList<string>> FromFile(string fileName)
    {
        foreach (IList<string> item in FromFile(fileName, ignoreFirstLineDefault)) yield return item;
    }

    public static IEnumerable<IList<string>> FromFile(string fileName, bool ignoreFirstLine)
    {
        using (StreamReader rdr = new StreamReader(fileName))
        {
            foreach(IList<string> item in FromReader(rdr, ignoreFirstLine)) yield return item;
        }
    }

    public static IEnumerable<IList<string>> FromStream(Stream csv)
    {
        foreach (IList<string> item in FromStream(csv, ignoreFirstLineDefault)) yield return item;
    }

    public static IEnumerable<IList<string>> FromStream(Stream csv, bool ignoreFirstLine)
    {
        using (var rdr = new StreamReader(csv))
        {
            foreach (IList<string> item in FromReader(rdr, ignoreFirstLine)) yield return item;
        }
    }

    public static IEnumerable<IList<string>> FromReader(TextReader csv)
    {
        //Probably should have used TextReader instead of StreamReader
        foreach (IList<string> item in FromReader(csv, ignoreFirstLineDefault)) yield return item;
    }

    public static IEnumerable<IList<string>> FromReader(TextReader csv, bool ignoreFirstLine)
    {
        if (ignoreFirstLine) csv.ReadLine();

        IList<string> result = new List<string>();

        StringBuilder curValue = new StringBuilder();
        char c;
        c = (char)csv.Read();
        while (csv.Peek() != -1)
        {
            switch (c)
            {
                case ',': //empty field
                    result.Add("");
                    c = (char)csv.Read();
                    break;
                case '"': //qualified text
                case '\'':
                    char q = c;
                    c = (char)csv.Read();
                    bool inQuotes = true;
                    while (inQuotes && csv.Peek() != -1)
                    {
                        if (c == q)
                        {
                            c = (char)csv.Read();
                            if (c != q)
                                inQuotes = false;
                        }

                        if (inQuotes)
                        {
                            curValue.Append(c);
                            c = (char)csv.Read();
                        } 
                    }
                    result.Add(curValue.ToString());
                    curValue = new StringBuilder();
                    if (c == ',') c = (char)csv.Read(); // either ',', newline, or endofstream
                    break;
                case '\n': //end of the record
                case '\r':
                    //potential bug here depending on what your line breaks look like
                    if (result.Count > 0) // don't return empty records
                    {
                        yield return result;
                        result = new List<string>();
                    }
                    c = (char)csv.Read();
                    break;
                default: //normal unqualified text
                    while (c != ',' && c != '\r' && c != '\n' && csv.Peek() != -1)
                    {
                        curValue.Append(c);
                        c = (char)csv.Read();
                    }
                    result.Add(curValue.ToString());
                    curValue = new StringBuilder();
                    if (c == ',') c = (char)csv.Read(); //either ',', newline, or endofstream
                    break;
            }

        }
        if (curValue.Length > 0) //potential bug: I don't want to skip on a empty column in the last record if a caller really expects it to be there
            result.Add(curValue.ToString());
        if (result.Count > 0) 
            yield return result;

    }
    private static bool ignoreFirstLineDefault = false;
}
26
ответ дан 1 December 2019 в 17:11
поделиться

Мне очень нравится библиотека FileHelpers . Это быстро, это 100% C #, он доступен БЕСПЛАТНО , очень гибкий и простой в использовании.

8
ответ дан 1 December 2019 в 17:11
поделиться

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

Если вы просто пытаетесь прочитать файл CSV с C # проще всего использовать класс Microsoft.VisualBasic.FileIO.TextFieldParser . На самом деле он встроен в .NET Framework, а не является сторонним расширением.

Да, он находится в Microsoft.VisualBasic.dll , но это не значит, что вы не можете его использовать. из C # (или любого другого языка CLR).

Вот пример использования, взятый из документации MSDN :

Using MyReader As New _
Microsoft.VisualBasic.FileIO.TextFieldParser("C:\testfile.txt")
   MyReader.TextFieldType = FileIO.FieldType.Delimited
   MyReader.SetDelimiters(",")
   Dim currentRow As String()
   While Not MyReader.EndOfData
      Try
         currentRow = MyReader.ReadFields()
         Dim currentField As String
         For Each currentField In currentRow
            MsgBox(currentField)
         Next
      Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
      MsgBox("Line " & ex.Message & _
      "is not valid and will be skipped.")
      End Try
   End While
End Using

Опять же, этот пример находится в VB.NET, но было бы тривиально переведите его на C #.

21
ответ дан 1 December 2019 в 17:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: