CSV-fil Importen i .Net

stemmer
100

Jeg skjønner at dette er en nybegynner spørsmål, men jeg leter etter en enkel løsning - det virker som det skal være ett.

Hva er den beste måten å importere en CSV-fil til en sterkt-skrev datastruktur? Igjen enkle = bedre.

Publisert på 05/08/2008 klokken 04:43
kilden bruker
På andre språk...                            


12 svar

stemmer
72

Microsofts TextFieldParser er stabil og følger RFC 4180 for CSV-filer. Ikke la deg skremme av Microsoft.VisualBasicnamespace; det er en standard komponent i .NET Framework, bare legge en referanse til den globale Microsoft.VisualBasicmontering.

Hvis du kompilering for Windows (i motsetning til Mono) og regner ikke med å måtte analysere "ødelagt" (non-RFC-kompatibel) CSV-filer, da dette ville være det opplagte valget, som det er gratis, ubegrenset, stabil, og aktivt støttet, hvorav de fleste kan ikke sies for FileHelpers.

Se også: Hvordan: Les Fra kommaseparert tekstfiler i Visual Basic for en VB kode eksempel.

Svarte 01/04/2009 kl. 19:58
kilden bruker

stemmer
48

Sjekk ut FileHelpers Open Source Library .

Svarte 05/08/2008 kl. 04:47
kilden bruker

stemmer
21

Bruk en OLEDB tilkobling.

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();
Svarte 05/11/2008 kl. 14:41
kilden bruker

stemmer
12

Hvis du venter ganske komplekse scenarier for CSV parsing, ikke engang tenke opp med å rulle vår egen parser . Det finnes en rekke gode verktøy der ute, som FileHelpers , eller de fra CodeProject .

Poenget er at dette er et ganske vanlig problem, og du kan satse på at mye av programvareutviklere har allerede tenkt på og løst dette problemet.

Svarte 16/08/2008 kl. 23:44
kilden bruker

stemmer
9

Jeg er enig med @ NotMyself . FileHelpers er godt testet og håndterer alle typer edge saker som du vil til slutt nødt til å forholde seg til hvis du gjør det selv. Ta en titt på hva FileHelpers gjør, og bare skrive din egen hvis du er helt sikker på at enten (1) vil du aldri trenger å håndtere edge tilfeller FileHelpers gjør, eller (2) du elsker å skrive denne typen ting og kommer til å være overlykkelig når du må analysere ting som dette:

1, "Bill", "Smith", "Supervisor", "Ingen kommentar"

2, 'Drake,', 'O'Malley », Vaktmester,

Oops, jeg er ikke sitert og jeg er på en ny linje!

Svarte 16/08/2008 kl. 23:53
kilden bruker

stemmer
9

Brian gir en fin løsning for å konvertere den til et sterkt skrevet samling.

De fleste av CSV analysemetodene som er gitt ikke tar hensyn rømmer felt eller noen av de andre spissfindigheter i CSV-filer (som trimming felt). Her er koden jeg personlig bruker. Det er litt røff i kantene, og har stort sett ingen feilrapportering.

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

Merk at dette ikke håndterer kanten tilfelle av felt ikke blir deliminated av doble anførselstegn, men meerley ha en sitert streng på innsiden av det. Se dette innlegget for litt av et bedre expanation samt noen linker til noen skikkelig biblioteker.

Svarte 08/08/2008 kl. 16:20
kilden bruker

stemmer
6

Jeg var lei så jeg endret noen ting jeg skrev. Det prøve er å kapsle analyser i en OO måte whle kutte ned på mengden av gjentakelser gjennom filen, det bare gjentas en gang på toppen 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]),
                };
            }
        }
    }
}
Svarte 08/08/2008 kl. 09:39
kilden bruker

stemmer
5

Det er to artikler om CodeProject som gir kode for en løsning, en som bruker StreamReader og en som importerer CSV-data ved hjelp av Microsoft Tekst Driver .

Svarte 05/08/2008 kl. 05:24
kilden bruker

stemmer
2

En god enkel måte å gjøre det på er å åpne filen, og lese hver linje i en matrise, lenket liste, data-struktur-of-your-valg. Vær forsiktig med håndtering av den første linjen skjønt.

Dette kan være over hodet, men det synes å være en direkte måte å få tilgang til dem også ved hjelp av en tilkoblingsstreng .

Hvorfor ikke prøve å bruke Python i stedet for C # eller VB? Den har en fin CSV-modulen til import som gjør alle de tunge løftene for deg.

Svarte 05/08/2008 kl. 04:49
kilden bruker

stemmer
1

Jeg skrev i noen kode. Resultatet i datagridviewer så bra. Den analyserer en enkelt linje med tekst til en Arraylist av objekter.

    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;
    }
Svarte 09/09/2011 kl. 10:02
kilden bruker

stemmer
1

Jeg måtte bruke en CSV parser i .NET for et prosjekt i sommer og bosatte seg på Microsoft Jet Text Driver. Du angir en mappe ved hjelp av en tilkoblingsstreng, så spørre en fil ved hjelp av en SQL SELECT-setningen. Du kan spesifisere sterke typer med en schema.ini fil. Jeg gjorde ikke dette i begynnelsen, men da jeg begynte å bli dårlige resultater der den type data var ikke umiddelbart klart, for eksempel IP-tall eller en oppføring som "XYQ 3.9 SP1".

En begrensning Jeg kjørte inn er at den ikke kan håndtere kolonnenavnene ovenfor 64 tegn; det avkorter. Dette bør ikke være et problem, bortsett fra at jeg var arbeider med svært dårlig utformet inndata. Den returnerer en ADO.NET datasett.

Dette var den beste løsningen jeg fant. Jeg ville være skeptisk til å rulle min egen CSV parser, siden jeg ville trolig gå glipp av noen av ende tilfeller, og jeg fant ikke noen andre gratis CSV parsing pakker for .NET ute.

EDIT: Dessuten kan det bare være en schema.ini fil per katalog, så jeg dynamisk føyd til det sterkt å skrive de nødvendige kolonnene. Det vil bare sterkt-skriver kolonnene spesifisert, og antyde for noen uspesifisert felt. Jeg virkelig pris på dette, som jeg ble håndtere import av en væske 70 + kolonne CSV, og ønsker ikke å spesifisere hver kolonne, bare Den ordentlig seg.

Svarte 16/08/2008 kl. 22:15
kilden bruker

stemmer
0

Hvis du kan garantere at det ikke er noen komma i dataene, så den enkleste måten ville trolig være å bruke String.split .

For eksempel:

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

Det kan være biblioteker du kan bruke til å hjelpe, men det er trolig like enkelt som du kan få. Bare pass på at du ikke kan ha komma i dataene, ellers må du analysere det bedre.

Svarte 05/08/2008 kl. 05:02
kilden bruker

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