Import pliku CSV w .NET

głosy
99

Zdaję sobie sprawę, że jest to kwestia początkujących, ale szukam proste rozwiązanie - wydaje się, że powinien być jeden.

Jaki jest najlepszy sposób, aby zaimportować plik CSV do silnie wpisany struktury danych? Ponownie proste = lepiej.

Utwórz 05/08/2008 o 05:43
źródło użytkownik
W innych językach...                            


12 odpowiedzi

głosy
48

Sprawdź FileHelpers Open Source Library .

Odpowiedział 05/08/2008 o 05:47
źródło użytkownik

głosy
2

Dobrym prosty sposób to zrobić, to otworzyć plik i przeczytać każdy wiersz do tablicy, połączonej listy danych, struktura-of-your-wyboru. Należy zwracać uwagę na obsługę pierwszą linię chociaż.

Może to być nad głową, ale nie wydaje się być bezpośredni sposób dostępu do nich, jak również przy użyciu ciąg połączenia .

Dlaczego nie spróbować użyć Python zamiast C # lub VB? Ma ładny moduł CSV do importowania, że ​​nie wszystkie podnoszenia ciężkich dla Ciebie.

Odpowiedział 05/08/2008 o 05:49
źródło użytkownik

głosy
0

Jeśli można zagwarantować, że nie istnieją żadne przecinki w danych, to najprostszym sposobem będzie prawdopodobnie używać String.split .

Na przykład:

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

Nie mogą być biblioteki można użyć, aby pomóc, ale to chyba tak proste, jak można dostać. Wystarczy upewnić się, że nie można mieć przecinki w danych, w przeciwnym razie trzeba będzie analizować to lepiej.

Odpowiedział 05/08/2008 o 06:02
źródło użytkownik

głosy
5

Istnieją dwa artykułów na CodeProject, które zapewniają kodu rozwiązania, jednego, który używa StreamReader i jeden, który importuje dane CSV za pomocą tekstu sterownik Microsoft .

Odpowiedział 05/08/2008 o 06:24
źródło użytkownik

głosy
6

Byłem znudzony więc modyfikować niektóre rzeczy napisałem. To spróbuj do hermetyzacji analizowania w sposób OO whle wycinanie od ilości iteracji za pośrednictwem pliku, a jedynie iteracje raz na najwyższym 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]),
                };
            }
        }
    }
}
Odpowiedział 08/08/2008 o 10:39
źródło użytkownik

głosy
9

Brian daje miłe rozwiązanie dla konwersji do silnie typami kolekcji.

Większość metod analizowania danych CSV nie uwzględniają uciekających pól lub niektórych innych subtelności plików CSV (takich dziedzinach Kadrowanie). Oto kod Osobiście korzystam. To trochę szorstkie na brzegach i ma prawie żadnego raportowanie błędów.

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

Zauważ, że nie radzi sobie sprawę krawędzi pól nie jest deliminated przez cudzysłów, ale meerley o cudzysłowie wewnątrz niego. Zobacz ten post na trochę lepsze expanation jak również kilka linków do niektórych odpowiednich bibliotek.

Odpowiedział 08/08/2008 o 17:20
źródło użytkownik

głosy
1

Musiałem użyć parsera CSV w .NET dla projektu latem tego roku i osiadł na tekście Sterownik Microsoft Jet. Określić folder przy użyciu ciąg połączenia, a następnie plik kwerendy przy użyciu SQL SELECT. Można określić mocne typy używając Schema.ini pliku. Nie zrobiłem tego na początku, ale potem było coraz złe wyniki, gdzie typ danych nie było od razu widoczne, takie jak numery IP lub wpisu jak „XYQ 3.9 SP1”.

Jednym z ograniczeń wpadłem na to, że nie poradzi sobie nazwy kolumn powyżej 64 znaków; to obcina. To nie powinno być problemu, chyba mam do czynienia z bardzo źle zaprojektowanych danych wejściowych. Zwraca DataSet ADO.NET.

To było najlepsze rozwiązanie znalazłem. Byłbym ostrożny toczenia własne CSV parser, ponieważ to pewnie brakuje niektórych przypadkach końcowych, a nie mogę znaleźć żadnych innych pakietów analizowania wolne CSV NET tam.

EDIT: Ponadto, nie może być tylko jeden plik Schema.ini na katalogu, więc dynamicznie dołączane do niego mocno wpisać potrzebne kolumny. To dopiero będzie silnie typ kolumny określone i wnioskować o jakiejkolwiek dziedzinie nieokreślony. Naprawdę doceniam to, co mam do czynienia z importem płyn 70+ kolumny CSV i nie chcą podać każdą kolumnę, tylko te, które niewłaściwie.

Odpowiedział 16/08/2008 o 23:15
źródło użytkownik

głosy
12

Jeśli spodziewasz się dość skomplikowane scenariusze CSV parsowania, nawet nie myśl nawet toczenia własne parsera . Istnieje wiele doskonałych narzędzi tam, jak FileHelpers , a nawet te z CodeProject .

Chodzi o to, że jest to dość powszechny problem i można założyć, że wielu programistów już myślał o i rozwiązać ten problem.

Odpowiedział 17/08/2008 o 00:44
źródło użytkownik

głosy
9

Zgadzam się z @ NotMyself . FileHelpers jest dobrze przetestowane i obsługuje wszystkie rodzaje przypadków brzegowych, że w końcu będziesz mieć do czynienia, jeśli robisz to sam. Spójrz na to, co robi i FileHelpers tylko napisać własną rękę, jeśli jesteś absolutnie pewien, że albo (1) nigdy nie będziesz musiał obsługiwać przypadki brzegowe FileHelpers robi, albo (2) kochasz pisania tego rodzaju rzeczy i idą do być uszczęśliwiony, gdy trzeba analizować rzeczy tak:

1, "Bill", "Smith", "Opiekun", "No Comment"

2, 'Drake', 'O'Malley', "Woźny,

Ups, nie będę cytował, a ja jestem na nowej linii!

Odpowiedział 17/08/2008 o 00:53
źródło użytkownik

głosy
21

Użyj połączenia 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();
Odpowiedział 05/11/2008 o 15:41
źródło użytkownik

głosy
72

Microsoft TextFieldParser jest stabilny i podąża RFC 4180 dla plików CSV. Nie zniechęcaj się przez Microsoft.VisualBasicnazw; jest to standardowy komponent w .NET Framework, wystarczy dodać odwołanie do globalnego Microsoft.VisualBasiczespołu.

Jeśli kompilacji dla Windows (w przeciwieństwie do Mono) i nie przewidujemy konieczności analizowania „broken” (non-RFC zgodny) plików CSV, to byłoby oczywistym wyborem, ponieważ jest wolny, nieograniczony, stabilny, i aktywnie wspierał, z których większość nie można powiedzieć o FileHelpers.

Zobacz także: Jak: odczytać z plików rozdzielanych przecinkami Tekst w języku Visual Basic dla przykładu kodu VB.

Odpowiedział 01/04/2009 o 20:58
źródło użytkownik

głosy
1

Wpisałem w niektórych kodu. Wynik w datagridviewer wyglądał dobrze. Analizuje pojedynczą linię tekstu ArrayList obiektów.

    enum quotestatus
    {
        none,
        firstquote,
        secondquote
    }
    public static System.Collections.ArrayList Parse(string line,string delimiter)
    {        
        System.Collections.ArrayList ar = new System.Collections.ArrayList();
        StringBuilder field = new StringBuilder();
        quotestatus status = quotestatus.none;
        foreach (char ch in line.ToCharArray())
        {                                
            string chOmsch = "char";
            if (ch == Convert.ToChar(delimiter))
            {
                if (status== quotestatus.firstquote)
                {
                    chOmsch = "char";
                }                         
                else
                {
                    chOmsch = "delimiter";                    
                }                    
            }

            if (ch == Convert.ToChar(34))
            {
                chOmsch = "quotes";           
                if (status == quotestatus.firstquote)
                {
                    status = quotestatus.secondquote;
                }
                if (status == quotestatus.none )
                {
                    status = quotestatus.firstquote;
                }
            }

            switch (chOmsch)
            {
                case "char":
                    field.Append(ch);
                    break;
                case "delimiter":                        
                    ar.Add(field.ToString());
                    field.Clear();
                    break;
                case "quotes":
                    if (status==quotestatus.firstquote)
                    {
                        field.Clear();                            
                    }
                    if (status== quotestatus.secondquote)
                    {                                                                           
                            status =quotestatus.none;                                
                    }                    
                    break;
            }
        }
        if (field.Length != 0)            
        {
            ar.Add(field.ToString());                
        }           
        return ar;
    }
Odpowiedział 09/09/2011 o 11:02
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more