c# - CSV-Dateiimporte in .Net

Translate

Mir ist klar, dass dies eine neue Frage ist, aber ich suche nach einer einfachen Lösung - es scheint, als sollte es eine geben.

Wie kann eine CSV-Datei am besten in eine stark typisierte Datenstruktur importiert werden? Wieder einfach = besser.

This question and all comments follow the "Attribution Required."

Alle Antworten

Translate

MicrosoftTextFieldParserist stabil und folgtRFC 4180für CSV-Dateien. Lassen Sie sich nicht von derMicrosoft.VisualBasicNamespace; Es ist eine Standardkomponente in .NET Framework. Fügen Sie einfach einen Verweis auf die globale Komponente hinzuMicrosoft.VisualBasicVersammlung.

Wenn Sie für Windows kompilieren (im Gegensatz zu Mono) und nicht damit rechnen müssen, "kaputte" (nicht RFC-kompatible) CSV-Dateien zu analysieren, ist dies die naheliegende Wahl, da es kostenlos, uneingeschränkt und stabil ist. und aktiv unterstützt, von denen die meisten für FileHelpers nicht gesagt werden können.

Siehe auch:Gewusst wie: Lesen aus durch Kommas getrennten Textdateien in Visual Basicfür ein VB-Codebeispiel.

Quelle
Translate

Verwenden Sie eine OleDB-Verbindung.

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();
Quelle
ICR
Translate

Wenn Sie ziemlich komplexe Szenarien für die CSV-Analyse erwarten,Denken Sie nicht einmal daran, unseren eigenen Parser zu rollen. Es gibt viele exzellente Tools wieFileHelpersoder sogar vonCodeProject.

Der Punkt ist, dass dies ein ziemlich häufiges Problem ist und man könnte darauf wettenvielvon Softwareentwicklern haben bereits über dieses Problem nachgedacht und es gelöst.

Quelle
Translate

Brian bietet eine gute Lösung für die Konvertierung in eine stark typisierte Sammlung.

Die meisten der angegebenen CSV-Analysemethoden berücksichtigen keine Escape-Felder oder einige andere Feinheiten von CSV-Dateien (wie das Trimmen von Feldern). Hier ist der Code, den ich persönlich benutze. Es ist ein bisschen rau an den Rändern und hat so gut wie keine Fehlerberichterstattung.

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

Beachten Sie, dass dies nicht den Randfall von Feldern behandelt, die nicht durch doppelte Anführungszeichen getrennt werden, sondern von Meerley, der eine Zeichenfolge in Anführungszeichen enthält. Sehendieser Beitragfür eine etwas bessere Erweiterung sowie einige Links zu einigen richtigen Bibliotheken.

Quelle
Translate

Ich bin einverstanden mit @Nicht ich. FileHelpersist gut getestet und behandelt alle Arten von Randfällen, mit denen Sie sich eventuell befassen müssen, wenn Sie es selbst tun. Schauen Sie sich an, was FileHelpers macht, und schreiben Sie nur dann Ihre eigenen, wenn Sie absolut sicher sind, dass Sie entweder (1) niemals die Randfälle von FileHelpers behandeln müssen oder (2) Sie diese Art von Dingen gerne schreiben und dies tun werden Seien Sie überglücklich, wenn Sie solche Dinge analysieren müssen:

1, "Bill", "Smith", "Supervisor", "No Comment"

2, 'Drake', 'O'Malley', "Hausmeister,

Ups, ich werde nicht zitiert und bin in einer neuen Zeile!

Quelle
Translate

Ich war gelangweilt, also habe ich einige Sachen modifiziert, die ich geschrieben habe. Es wird versucht, das Parsing auf OO-Weise zu kapseln, während die Anzahl der Iterationen durch die Datei verringert wird. Es wird nur einmal oben für jede Iteration wiederholt.

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]),
                };
            }
        }
    }
}
Quelle
Translate

Es gibt zwei Artikel auf CodeProject, die Code für eine Lösung bereitstellen, einen, der verwendetStreamReaderund eine davonimportiert CSV-DatenVerwendung derMicrosoft Text Driver.

Quelle
Translate

Eine gute einfache Möglichkeit besteht darin, die Datei zu öffnen und jede Zeile in ein Array, eine verknüpfte Liste und eine Datenstruktur Ihrer Wahl einzulesen. Seien Sie jedoch vorsichtig beim Umgang mit der ersten Zeile.

Dies mag über Ihrem Kopf liegen, aber es scheint eine direkte Möglichkeit zu geben, auch mit a auf sie zuzugreifenVerbindungszeichenfolge.

Warum nicht versuchen, Python anstelle von C # oder VB zu verwenden? Es hat ein schönes CSV-Modul zum Importieren, das das ganze schwere Heben für Sie erledigt.

Quelle
Translate

Ich musste diesen Sommer einen CSV-Parser in .NET für ein Projekt verwenden und entschied mich für den Microsoft Jet Text Driver. Sie geben einen Ordner mithilfe einer Verbindungszeichenfolge an und fragen dann eine Datei mithilfe einer SQL Select-Anweisung ab. Sie können starke Typen mithilfe einer schema.ini-Datei angeben. Ich habe dies zuerst nicht getan, aber dann bekam ich schlechte Ergebnisse, bei denen der Datentyp nicht sofort ersichtlich war, wie z. B. IP-Nummern oder ein Eintrag wie "XYQ 3.9 SP1".

Eine Einschränkung, auf die ich gestoßen bin, ist, dass es keine Spaltennamen mit mehr als 64 Zeichen verarbeiten kann. es schneidet ab. Dies sollte kein Problem sein, außer ich hatte es mit sehr schlecht gestalteten Eingabedaten zu tun. Es gibt ein ADO.NET DataSet zurück.

Dies war die beste Lösung, die ich gefunden habe. Ich wäre vorsichtig, wenn ich meinen eigenen CSV-Parser rollen würde, da ich wahrscheinlich einige der Endfälle verpassen würde und ich keine anderen kostenlosen CSV-Parsing-Pakete für .NET gefunden habe.

BEARBEITEN: Außerdem kann es nur eine schema.ini-Datei pro Verzeichnis geben, daher habe ich sie dynamisch angehängt, um die erforderlichen Spalten stark einzugeben. Es werden nur die angegebenen Spalten stark eingegeben und auf nicht angegebene Felder geschlossen. Ich habe dies sehr geschätzt, da ich mich mit dem Import einer flüssigen 70+ Spalten-CSV befasste und nicht jede Spalte angeben wollte, sondern nur die sich schlecht benehmenden.

Quelle
Translate

Ich habe einen Code eingegeben. Das Ergebnis im Datagridviewer sah gut aus. Es analysiert eine einzelne Textzeile in einer Arrayliste von Objekten.

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

Wenn Sie garantieren können, dass die Daten keine Kommas enthalten, ist die Verwendung wahrscheinlich der einfachsteString.split.

Zum Beispiel:

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

Möglicherweise gibt es Bibliotheken, mit denen Sie helfen können, aber das ist wahrscheinlich so einfach wie möglich. Stellen Sie nur sicher, dass die Daten keine Kommas enthalten können, da Sie sie sonst besser analysieren müssen.

Quelle