Файл CSV импорта к структуре данных со строгим контролем типов в [закрытом] .NET

Что лучший способ состоит в том, чтобы импортировать файл CSV в структуру данных со строгим контролем типов?

104
задан KyleMit 21 November 2019 в 21:56
поделиться

11 ответов

51
ответ дан Marcos Meli 24 November 2019 в 04:10
поделиться

Если можно гарантировать, что нет никаких запятых в данных, то самый простой путь состоял бы в том, чтобы, вероятно, использовать String.split.

, Например:

String[] values = myString.Split(',');
myObject.StringField = values[0];
myObject.IntField = Int32.Parse(values[1]);

могут быть библиотеки, которыми Вы могли пользоваться к справке, но это, вероятно, так просто, как можно добраться. Просто удостоверьтесь, что у Вас не может быть запятых в данных, иначе необходимо будет проанализировать их лучше.

0
ответ дан Mike Stone 24 November 2019 в 04:10
поделиться

Я должен был использовать синтаксический анализатор CSV в.NET для проекта этим летом и обоснованный на текстовом Драйвере Microsoft Jet. Вы определяете папку с помощью строки подключения, затем запрашиваете файл с помощью оператора SQL Select. Можно определить сильные типы с помощью файла schema.ini. Я не сделал этого сначала, но тогда я получал плохие результаты, где тип данных не был сразу очевиден, таков как IP-адреса или запись как "XYQ 3.9 SP1".

Одно ограничение, с которым я столкнулся, - то, что это не может обработать имена столбцов выше 64 символов; это усекает. Это не должно быть проблемой, кроме я имел дело с очень плохо разработанными входными данными. Это возвращает ADO.NET DataSet.

Это было лучшим решением, которое я нашел. Я опасался бы прокручивать свой собственный синтаксический анализатор CSV, так как я, вероятно, пропущу некоторые случаи конца, и я не нашел никакие другие бесплатные пакеты парсинга CSV для.NET там.

РЕДАКТИРОВАНИЕ: Кроме того, может только быть один файл schema.ini на каталог, таким образом, я динамично добавил к нему для сильного ввода необходимых столбцов. Это только сильно-введет столбцы, определенные, и выведет для любого неуказанного поля. Я действительно ценил это, поскольку я имел дело с импортом жидких 70 + столбец CSV и не хотел определять каждый столбец, только неправильно себя ведущие.

1
ответ дан pbh101 24 November 2019 в 04:10
поделиться

Существует две статьи о CodeProject, которые обеспечивают код для решения, то, которое использует StreamReader и тот что данные CSV импорта использование текстовый Драйвер .

Microsoft
5
ответ дан gonzobrains 24 November 2019 в 04:10
поделиться

Я скучал так, я изменил некоторый материал, который я записал. Это попытка инкапсулировать парсинг способом OO whle сокращающий объема повторений через файл, это только выполняет итерации однажды наверху foreach.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

namespace ConsoleApplication1
{
    class Program
    {

        static void Main(string[] args)
        {

            // usage:

            // note this wont run as getting streams is not Implemented

            // but will get you started

            CSVFileParser fileParser = new CSVFileParser();

            // TO Do:  configure fileparser

            PersonParser personParser = new PersonParser(fileParser);

            List<Person> persons = new List<Person>();
            // if the file is large and there is a good way to limit
            // without having to reparse the whole file you can use a 
            // linq query if you desire
            foreach (Person person in personParser.GetPersons())
            {
                persons.Add(person);
            }

            // now we have a list of Person objects
        }
    }

    public abstract  class CSVParser 
    {

        protected String[] deliniators = { "," };

        protected internal IEnumerable<String[]> GetRecords()
        {

            Stream stream = GetStream();
            StreamReader reader = new StreamReader(stream);

            String[] aRecord;
            while (!reader.EndOfStream)
            {
                  aRecord = reader.ReadLine().Split(deliniators,
                   StringSplitOptions.None);

                yield return aRecord;
            }

        }

        protected abstract Stream GetStream(); 

    }

    public class CSVFileParser : CSVParser
    {
        // to do: add logic to get a stream from a file

        protected override Stream GetStream()
        {
            throw new NotImplementedException();
        } 
    }

    public class CSVWebParser : CSVParser
    {
        // to do: add logic to get a stream from a web request

        protected override Stream GetStream()
        {
            throw new NotImplementedException();
        }
    }

    public class Person
    {
        public String Name { get; set; }
        public String Address { get; set; }
        public DateTime DOB { get; set; }
    }

    public class PersonParser 
    {

        public PersonParser(CSVParser parser)
        {
            this.Parser = parser;
        }

        public CSVParser Parser { get; set; }

        public  IEnumerable<Person> GetPersons()
        {
            foreach (String[] record in this.Parser.GetRecords())
            {
                yield return new Person()
                {
                    Name = record[0],
                    Address = record[1],
                    DOB = DateTime.Parse(record[2]),
                };
            }
        }
    }
}
6
ответ дан Ant Swift 24 November 2019 в 04:10
поделиться

Хороший простой способ сделать это состоит в том, чтобы открыть файл и считать каждую строку в массив, связанный список, data-structure-of-your-choice. Будьте осторожны относительно обработки первой строки все же.

Это может находиться вне Вашего понимания, но там, кажется, прямой способ получить доступ к ним также использование строка подключения .

, Почему бы не попытаться использовать Python вместо C# или VB? Это имеет хороший модуль CSV для импорта, который делает весь тяжелый подъем для Вас.

2
ответ дан halfer 24 November 2019 в 04:10
поделиться

Brian дает хорошее решение для преобразования его к набору со строгим контролем типов.

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

public static IList<IList<string>> Parse(string content)
{
    IList<IList<string>> records = new List<IList<string>>();

    StringReader stringReader = new StringReader(content);

    bool inQoutedString = false;
    IList<string> record = new List<string>();
    StringBuilder fieldBuilder = new StringBuilder();
    while (stringReader.Peek() != -1)
    {
        char readChar = (char)stringReader.Read();

        if (readChar == '\n' || (readChar == '\r' && stringReader.Peek() == '\n'))
        {
            // If it's a \r\n combo consume the \n part and throw it away.
            if (readChar == '\r')
            {
                stringReader.Read();
            }

            if (inQoutedString)
            {
                if (readChar == '\r')
                {
                    fieldBuilder.Append('\r');
                }
                fieldBuilder.Append('\n');
            }
            else
            {
                record.Add(fieldBuilder.ToString().TrimEnd());
                fieldBuilder = new StringBuilder();

                records.Add(record);
                record = new List<string>();

                inQoutedString = false;
            }
        }
        else if (fieldBuilder.Length == 0 && !inQoutedString)
        {
            if (char.IsWhiteSpace(readChar))
            {
                // Ignore leading whitespace
            }
            else if (readChar == '"')
            {
                inQoutedString = true;
            }
            else if (readChar == ',')
            {
                record.Add(fieldBuilder.ToString().TrimEnd());
                fieldBuilder = new StringBuilder();
            }
            else
            {
                fieldBuilder.Append(readChar);
            }
        }
        else if (readChar == ',')
        {
            if (inQoutedString)
            {
                fieldBuilder.Append(',');
            }
            else
            {
                record.Add(fieldBuilder.ToString().TrimEnd());
                fieldBuilder = new StringBuilder();
            }
        }
        else if (readChar == '"')
        {
            if (inQoutedString)
            {
                if (stringReader.Peek() == '"')
                {
                    stringReader.Read();
                    fieldBuilder.Append('"');
                }
                else
                {
                    inQoutedString = false;
                }
            }
            else
            {
                fieldBuilder.Append(readChar);
            }
        }
        else
        {
            fieldBuilder.Append(readChar);
        }
    }
    record.Add(fieldBuilder.ToString().TrimEnd());
    records.Add(record);

    return records;
}

Примечание, что это не обрабатывает пограничный случай полей, не являющихся deliminated двойными кавычками, но meerley наличие заключенной в кавычки строки в нем. См. это сообщение некоторое время лучшего expanation, а также некоторых ссылок на некоторые надлежащие библиотеки.

9
ответ дан Community 24 November 2019 в 04:10
поделиться

Если Вы ожидаете, что довольно сложные сценарии для парсинга CSV, даже не продумывают прокрутки нашего собственного синтаксического анализатора . Существует много превосходных инструментов там, как FileHelpers, или даже от CodeProject.

точка, это - довольно типичная проблема, и Вы могли держать пари, что много из разработчиков программного обеспечения уже думали об и решили эту проблему.

12
ответ дан Jon Limjap 24 November 2019 в 04:10
поделиться

Используйте Подключение OLEDB.

String sConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\InputDirectory\\;Extended Properties='text;HDR=Yes;FMT=Delimited'";
OleDbConnection objConn = new OleDbConnection(sConnectionString);
objConn.Open();
DataTable dt = new DataTable();
OleDbCommand objCmdSelect = new OleDbCommand("SELECT * FROM file.csv", objConn);
OleDbDataAdapter objAdapter1 = new OleDbDataAdapter();
objAdapter1.SelectCommand = objCmdSelect;
objAdapter1.Fill(dt);
objConn.Close();
21
ответ дан Dez 24 November 2019 в 04:10
поделиться

Я соглашаюсь с NotMyself. FileHelpers хорошо тестируется и обрабатывает все виды пограничных случаев, что необходимо будет в конечном счете иметь дело с тем, если Вы делаете это сами. Смотрите на то, что FileHelpers делает и только пишет Вашему собственному, если Вы абсолютно уверены, что любой (1) Вы никогда не должны будете обрабатывать пограничные случаи, которые FileHelpers делает, или (2) Вы любите писать этот вид материала и собираетесь быть очень счастливыми, когда необходимо проанализировать материал как это:

1, "счет", "Smith", "Супервизор", "Никакой Комментарий"

2, 'Drake', 'O'Malley', "Швейцар,

ой, я не заключаюсь в кавычки, и я нахожусь на новой строке!

9
ответ дан Community 24 November 2019 в 04:10
поделиться

TextFieldParser Microsoft стабилен и следует за RFC 4180 для файлов CSV. Не пугайтесь Microsoft.VisualBasic пространство имен; это - стандартный компонент в Платформе.NET, просто добавьте ссылку на глобальное Microsoft.VisualBasic блок.

Если Вы компилируете для Windows (в противоположность Моно) и не ожидаете иметь необходимость проанализировать "поврежденные" (non-RFC-compliant) файлы CSV, то это было бы очевидным выбором, поскольку это свободно, неограниченно, стабильно, и активно поддерживаемое, большинство которых не может быть сказано для FileHelpers.

См. также: Как к: Читайте Из Файлов Разделенного текста Запятой в Visual Basic для примера кода VB.

74
ответ дан Aaronaught 24 November 2019 в 04:10
поделиться
Другие вопросы по тегам:

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