CSV Importações de arquivo na Net

votos
99

Sei que esta é uma questão novato, mas eu estou procurando uma solução simples - parece que deve haver um.

Qual é a melhor maneira de importar um arquivo CSV em uma estrutura de dados fortemente tipado? Novamente = simples melhor.

Publicado 05/08/2008 em 05:43
fonte usuário
Em outras línguas...                            


12 respostas

votos
72

Da Microsoft TextFieldParser é estável e segue RFC 4180 para arquivos CSV. Não ser adiadas pelo Microsoft.VisualBasicnamespace; é um componente padrão do .NET Framework, basta adicionar uma referência para o global Microsoft.VisualBasicassembly.

Se você está compilando para Windows (ao contrário de Mono) e não antecipar ter que analisar "quebrado" arquivos CSV (não compatível com RFC), então esta seria a escolha óbvia, pois é livre, sem restrições, estável, e apoiou activamente, a maioria dos quais não pode ser dito para FileHelpers.

Veja também: Como: Leitura de arquivos de texto delimitado por vírgula em Visual Basic para um exemplo de código VB.

Respondeu 01/04/2009 em 20:58
fonte usuário

Respondeu 05/08/2008 em 05:47
fonte usuário

votos
21

Use uma conexão 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();
Respondeu 05/11/2008 em 15:41
fonte usuário

votos
12

Se você está esperando cenários bastante complexas para CSV parsing, nem sequer pensar-se de rolar o nosso próprio analisador . Há uma série de excelentes ferramentas para fora lá, como FileHelpers , ou mesmo os de CodeProject .

O ponto é que este é um problema bastante comum e você pode apostar que um monte de desenvolvedores de software já pensou e resolveu este problema.

Respondeu 17/08/2008 em 00:44
fonte usuário

votos
9

Concordo com @ NotMyself . FileHelpers é bem testado e lida com todos os tipos de casos de borda que você eventualmente tem que lidar com se você fazê-lo sozinho. Dê uma olhada no que FileHelpers não e apenas escrever o seu próprio, se você está absolutamente certo de que (1) você nunca vai precisar para lidar com os casos de ponta FileHelpers faz, ou (2) que você gosta de escrever este tipo de coisas e vão ser feliz quando você tem que analisar coisas como esta:

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

2, 'Drake,', 'O'Malley' ", zelador,

Opa, eu não estou citado e eu estou em uma nova linha!

Respondeu 17/08/2008 em 00:53
fonte usuário

votos
9

Brian dá uma solução agradável para convertê-lo para uma coleção fortemente tipado.

A maioria dos métodos de análise CSV dados não levam em conta campos de fuga ou alguns dos outros sutilezas de arquivos CSV (como campos de corte). Aqui está o código que eu uso pessoalmente. É um pouco áspero em torno das bordas e tem praticamente nenhum relato de erros.

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

Note que este não lidar com o caso beira de campos não sendo deliminated por aspas duplas, mas meerley ter uma string dentro dele. Veja este post para um pouco de uma melhor expanation, bem como alguns links para algumas bibliotecas adequadas.

Respondeu 08/08/2008 em 17:20
fonte usuário

votos
6

Eu estava entediado então eu modificado algumas coisas que eu escrevi. Ele tenta de encapsular a análise de uma maneira OO whle reduzindo a quantidade de iterações através do arquivo, ele apenas repete uma vez no topo 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]),
                };
            }
        }
    }
}
Respondeu 08/08/2008 em 10:39
fonte usuário

votos
5

Há dois artigos sobre CodeProject que fornecem código para uma solução, uma que usa StreamReader e que importa dados CSV usando o driver de texto Microsoft .

Respondeu 05/08/2008 em 06:24
fonte usuário

votos
2

Uma boa maneira simples de fazer isso é abrir o arquivo e ler cada linha em uma matriz, lista ligada, data-estrutura-de-seu-escolha. Tenha cuidado sobre como lidar com a primeira linha embora.

Isso pode ser sobre sua cabeça, mas não parece ser uma maneira direta para acessá-los bem usando uma seqüência de conexão .

Por que não tente usar Python em vez de C # ou VB? Ele tem um módulo CSV bom para importação que faz todo o trabalho pesado para você.

Respondeu 05/08/2008 em 05:49
fonte usuário

votos
1

Eu digitei em algum código. O resultado na datagridviewer parecia bom. Ele analisa uma única linha de texto para um ArrayList de objetos.

    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;
    }
Respondeu 09/09/2011 em 11:02
fonte usuário

votos
1

Eu tive que usar um analisador CSV em .NET para um projeto neste verão e se estabeleceram no driver de texto Microsoft Jet. Você especificar uma pasta usando uma seqüência de conexão, em seguida, consultar um arquivo usando uma instrução SQL Select. Você pode especificar tipos fortes usando um arquivo schema.ini. Eu não fiz isso no começo, mas então eu estava recebendo maus resultados, onde o tipo de dados não foi imediatamente aparente, como números de IP ou uma entrada como "XYQ 3.9 SP1".

Uma limitação eu corri para é que ele não consegue lidar com os nomes das colunas acima de 64 caracteres; ele trunca. Isso não deve ser um problema, só que eu estava lidando com dados de entrada muito mal concebidos. Ele retorna um DataSet ADO.NET.

Esta foi a melhor solução que eu encontrei. Eu seria cauteloso em rolando meu próprio analisador CSV, desde que eu provavelmente iria perder alguns dos casos fim, e eu não encontrou quaisquer outros pacotes analisar CSV livre para .NET lá fora.

EDIT: Além disso, só pode haver um arquivo schema.ini por diretório, então eu anexado dinamicamente para que a digitar fortemente as colunas necessárias. Só vai fortemente digite as colunas especificadas, e inferir para qualquer campo não especificado. I realmente apreciado, como eu estava lidando com a importação de um fluido 70 + coluna CSV e não quis especificar cada coluna, apenas os misbehaving.

Respondeu 16/08/2008 em 23:15
fonte usuário

votos
0

Se você pode garantir que não há vírgulas nos dados, em seguida, a maneira mais simples seria provavelmente usar String.split .

Por exemplo:

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

Pode haver bibliotecas que você pode usar para ajudar, mas isso é provavelmente tão simples como você pode começar. Apenas certifique-se que você não pode ter vírgulas nos dados, caso contrário você terá que analisá-lo melhor.

Respondeu 05/08/2008 em 06:02
fonte usuário

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