CSV-bestand De invoer in .Net

stemmen
99

Ik besef dat dit is een newbie vraag, maar ik ben op zoek naar een eenvoudige oplossing - het lijkt alsof er iemand zou moeten zijn.

Wat is de beste manier om een ​​CSV-bestand importeren in een sterk getypeerde datastructuur? Opnieuw eenvoudige = beter.

De vraag is gesteld op 05/08/2008 om 05:43
bron van user
In andere talen...                            


12 antwoorden

stemmen
72

Microsoft's TextFieldParser is stabiel en volgt RFC 4180 voor CSV-bestanden. Laat je niet afschrikken door de Microsoft.VisualBasicnamespace; het is een standaard component in het .NET Framework, een verwijzing toe te voegen aan de wereldwijde Microsoft.VisualBasicmontage.

Als u het samenstellen bent naar Windows (in tegenstelling tot Mono) en verwacht niet te hoeven "gebroken" (niet-RFC-compatibel) CSV-bestanden ontleden, dan zou dit voor de hand liggende keuze zijn, want het is gratis, onbeperkt, stabiel, en actief ondersteund, waarvan de meeste niet gezegd FileHelpers.

Zie ook: Hoe kan ik: Lees Van komma's gescheiden tekstbestanden in Visual Basic voor een VB code voorbeeld.

antwoordde op 01/04/2009 om 20:58
bron van user

stemmen
48

Check out FileHelpers Open Source Library .

antwoordde op 05/08/2008 om 05:47
bron van user

stemmen
21

Gebruik een OleDB verbinding.

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();
antwoordde op 05/11/2008 om 15:41
bron van user

stemmen
12

Als je verwacht vrij complexe scenario's voor CSV parsing, zelfs niet denken up van het rollend onze eigen parser . Er zijn een heleboel van uitstekende tools die er zijn, zoals FileHelpers , of zelfs degenen van CodeProject .

Het punt is dit een vrij veel voorkomend probleem en je kon wedden dat veel van software-ontwikkelaars al hebben nagedacht over en dit probleem opgelost.

antwoordde op 17/08/2008 om 00:44
bron van user

stemmen
9

Ik ben het met @ NotMyself . FileHelpers is goed getest en behandelt alle soorten van extreme gevallen dat je uiteindelijk te maken hebben met als je het zelf doen. Neem een kijkje op wat FileHelpers doet en alleen schrijf uw eigen als u zeker weet dat ofwel (1) hoeft u nooit meer te hanteren de rand gevallen FileHelpers doet, of (2) u houdt van het schrijven van dit soort dingen en gaan zijn dolblij als je moet dingen ontleden als volgt uit:

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

2, 'Drake', 'O'Malley' ', Portier,

Oeps, ik ben niet vermeld staat en ik ben op een nieuwe regel!

antwoordde op 17/08/2008 om 00:53
bron van user

stemmen
9

Brian geeft een mooie oplossing voor het converteren naar een sterk getypeerde collectie.

Het merendeel van de CSV parsing methoden gegeven geen rekening gehouden met het ontsnappen velden of enkele van de andere subtiliteiten van CSV-bestanden (zoals trimmen velden). Hier is de code die ik persoonlijk gebruik. Het is een beetje ruw rond de randen en heeft vrijwel geen fout rapportage.

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 op dat dit niet de rand geval van percelen niet wordt deliminated dubbele aanhalingstekens heeft te behandelen, maar meerley met een tekenreeks tussen aanhalingstekens binnenkant van het. Zie dit bericht voor een beetje een betere expanation evenals een aantal links naar een aantal goede bibliotheken.

antwoordde op 08/08/2008 om 17:20
bron van user

stemmen
6

Ik verveelde me dus ik aangepast enkele dingen die ik schreef. Het proberen om de parsing te kapselen in een OO manier whle bezuinigd op de hoeveelheid iteraties door middel van het bestand, maar herhaalt eenmaal aan de top 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]),
                };
            }
        }
    }
}
antwoordde op 08/08/2008 om 10:39
bron van user

stemmen
5

Er zijn twee artikelen over CodeProject die code voorziet in een oplossing, die gebruik maakt van StreamReader en een die CSV gegevens importeert met behulp van de Microsoft Text Driver .

antwoordde op 05/08/2008 om 06:24
bron van user

stemmen
2

Een goede eenvoudige manier om het te doen is om het bestand te openen, en te lezen elke regel in een array, gelinkte lijst, data-structuur-of-your-choice. Wees voorzichtig met het hanteren van de eerste regel dat wel.

Dit kan boven je hoofd, maar er lijkt een directe manier om ze te openen en het gebruik van een zijn connectie string .

Waarom niet proberen met behulp van Python in plaats van C # of VB? Het heeft een mooie CSV module te importeren dat al het zware werk voor je doet.

antwoordde op 05/08/2008 om 05:49
bron van user

stemmen
1

Ik typte in sommige code. Het resultaat in het datagridviewer zag er goed uit. Het analyseert een enkele regel tekst tot een ArrayList van objecten.

    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;
    }
antwoordde op 09/09/2011 om 11:02
bron van user

stemmen
1

Ik moest een CSV-parser te gebruiken in .NET voor een project deze zomer en afgerekend op de Microsoft Jet Text Driver. U specificeert een map met behulp van een verbinding string, ondervraag een bestand met een SQL Select-instructie. U kunt sterke types opgeven met een schema.ini bestand. Ik heb dit niet te doen op het eerste, maar toen kreeg ik slechte resultaten waarbij het type van de gegevens was niet meteen duidelijk, zoals IP-nummers of een regel als "XYQ 3.9 SP1".

Een beperking Ik kwam is dat het niet kan omgaan met namen van kolommen boven 64 tekens; Het kapt. Dit moet geen probleem zijn, behalve ik te maken had met een zeer slecht ontworpen invoergegevens. Het geeft een ADO.NET DataSet.

Dit was de beste oplossing die ik gevonden. Ik zou op hun hoede van het rollend mijn eigen CSV-parser te zijn, want ik zou waarschijnlijk een deel van het einde gevallen missen, en ik zag geen andere vrije CSV parsing pakketten te vinden voor NET die er zijn.

EDIT: Ook kan er maar één schema.ini bestand per map, dus ik dynamisch toegevoegd aan het aan sterk typt u de benodigde kolommen. Het zal alleen sterk typen de gespecificeerde kolommen en afleiden van niet gespecificeerde gebied. Ik ben erg tevreden dit, zoals ik te maken had met het importeren van een vloeistof 70+ kolom CSV en wilde niet elke kolom, alleen de misdragen degenen op te geven.

antwoordde op 16/08/2008 om 23:15
bron van user

stemmen
0

Als je kunt garanderen dat er geen komma's in de gegevens, dan zou de eenvoudigste manier waarschijnlijk te gebruiken String.split .

Bijvoorbeeld:

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

Er kunnen bibliotheken die u zou kunnen gebruiken om te helpen, maar dat is waarschijnlijk net zo eenvoudig als je kunt krijgen. Zorg ervoor dat je kunt geen komma's in de gegevens hebben, anders zal je nodig hebt om het beter te ontleden.

antwoordde op 05/08/2008 om 06:02
bron van user

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