Considerando que esta pergunta foi criada um ano antes de 1103495, acho que essa pergunta é uma duplicata desta.
MattH
2
Obrigado, Matt. Eu estava apenas tentando uni-los, não indicar qual veio primeiro. Você verá que tenho exatamente o mesmo texto na outra pergunta que aponta para esta. Existe uma maneira melhor de unir duas perguntas?
O TextFieldParser da Microsoft é estável e segue a RFC 4180 para arquivos CSV. Não desanime pelo Microsoft.VisualBasicnamespace; é um componente padrão no .NET Framework, basta adicionar uma referência ao Microsoft.VisualBasicconjunto global .
Se você está compilando para Windows (em oposição ao Mono) e não prevê ter que analisar arquivos CSV "quebrados" (não compatíveis com RFC), então esta seria a escolha óbvia, pois é gratuito, irrestrito, estável, e ativamente apoiado, a maioria dos quais não pode ser dito para FileHelpers.
Na verdade, não há nada específico do VB sobre essa classe além de seu namespace infelizmente nomeado. Definitivamente, eu escolheria esta biblioteca se só precisasse de um analisador CSV "simples", porque não há nada para baixar, distribuir ou se preocupar em geral. Para esse fim, editei a formulação com foco em VB dessa resposta.
Aaronaught,
@Aaronaught Acho que suas edições são principalmente uma melhoria. Embora esse RFC não seja necessariamente oficial, já que muitos escritores de CSV não o cumprem, por exemplo, o Excel nem sempre usa uma vírgula em arquivos "CSV". Além disso, minha resposta anterior já não dizia que a classe poderia ser usada em C #?
MarkJ de
O TextFieldParserfuncionará para delimitado por tabulação e outros dados estranhos gerados em Excel também. Eu percebo que a sua resposta anterior não estava afirmando que a biblioteca foi específico-VB, ele só veio até mim como implicando que foi realmente significou para VB, e não destina a ser usado em C #, que eu não acho que é o caso - existem algumas classes realmente úteis no MSVB.
Isso requer acesso ao sistema de arquivos. Pelo que eu sei, não há como fazer o OLEDB funcionar com streams na memória :(
UserControl,
3
@UserControl, é claro que requer acesso ao sistema de arquivos. Ele perguntou sobre a importação de um arquivo CSV
Kevin,
1
Eu não estou reclamando. Na verdade, eu preferiria a solução OLEDB em vez do resto, mas fiquei frustrado muitas vezes quando precisei analisar CSV em aplicativos ASP.NET e quis anotar isso.
UserControl
12
Se você está esperando cenários bastante complexos para a análise CSV, nem pense em lançar nosso próprio analisador . Existem muitas ferramentas excelentes por aí, como FileHelpers , ou mesmo algumas do CodeProject .
A questão é que este é um problema bastante comum e você pode apostar que muitos desenvolvedores de software já pensaram e resolveram esse problema.
Embora este link possa responder à pergunta, é melhor incluir as partes essenciais da resposta aqui e fornecer o link para referência. As respostas somente com link podem se tornar inválidas se a página vinculada mudar. - Da avaliação
techspider
Obrigado @techspider, espero que você tenha notado que este post foi do período beta do StackOverflow: D Dito isso, hoje em dia as ferramentas CSV são melhor obtidas a partir de pacotes Nuget - então não tenho certeza se mesmo as respostas dos links são imunes a 8 anos - antigos ciclos de evolução da tecnologia
Jon Limjap,
9
Brian oferece uma boa solução para convertê-lo em uma coleção fortemente tipada.
A maioria dos métodos de análise CSV fornecidos não leva em conta os campos de escape ou algumas das outras sutilezas dos arquivos CSV (como campos de corte). Aqui está o código que eu uso pessoalmente. É um pouco áspero nas bordas e praticamente não tem relatórios de erros.
publicstaticIList<IList<string>>Parse(string content){IList<IList<string>> records =newList<IList<string>>();StringReader stringReader =newStringReader(content);bool inQoutedString =false;IList<string> record =newList<string>();StringBuilder fieldBuilder =newStringBuilder();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 =newStringBuilder();
records.Add(record);
record =newList<string>();
inQoutedString =false;}}elseif(fieldBuilder.Length==0&&!inQoutedString){if(char.IsWhiteSpace(readChar)){// Ignore leading whitespace}elseif(readChar =='"'){
inQoutedString =true;}elseif(readChar ==','){
record.Add(fieldBuilder.ToString().TrimEnd());
fieldBuilder =newStringBuilder();}else{
fieldBuilder.Append(readChar);}}elseif(readChar ==','){if(inQoutedString){
fieldBuilder.Append(',');}else{
record.Add(fieldBuilder.ToString().TrimEnd());
fieldBuilder =newStringBuilder();}}elseif(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;}
Observe que isso não lida com o caso extremo de campos não serem delimitados por aspas duplas, mas apenas com uma string entre aspas. Veja este post para uma melhor expansão, bem como alguns links para algumas bibliotecas adequadas.
Eu concordo com @NotMyself . FileHelpers é bem testado e lida com todos os tipos de casos extremos com os quais você eventualmente terá que lidar se fizer isso sozinho. Dê uma olhada no que o FileHelpers faz e apenas escreva o seu próprio se você tiver certeza absoluta de que (1) você nunca precisará lidar com os casos extremos que o FileHelpers faz, ou (2) você adora escrever esse tipo de coisa e vai fique muito feliz quando tiver que analisar coisas como esta:
Eu estava entediado, então modifiquei algumas coisas que escrevi. Ele tenta encapsular a análise de uma maneira OO enquanto corta a quantidade de iterações no arquivo, itera apenas uma vez no primeiro foreach.
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.IO;namespaceConsoleApplication1{classProgram{staticvoidMain(string[] args){// usage:// note this wont run as getting streams is not Implemented// but will get you startedCSVFileParser fileParser =newCSVFileParser();// TO Do: configure fileparserPersonParser personParser =newPersonParser(fileParser);List<Person> persons =newList<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 desireforeach(Person person in personParser.GetPersons()){
persons.Add(person);}// now we have a list of Person objects}}publicabstractclassCSVParser{protectedString[] deliniators ={","};protectedinternalIEnumerable<String[]>GetRecords(){Stream stream =GetStream();StreamReader reader =newStreamReader(stream);String[] aRecord;while(!reader.EndOfStream){
aRecord = reader.ReadLine().Split(deliniators,StringSplitOptions.None);yieldreturn aRecord;}}protectedabstractStreamGetStream();}publicclassCSVFileParser:CSVParser{// to do: add logic to get a stream from a fileprotectedoverrideStreamGetStream(){thrownewNotImplementedException();}}publicclassCSVWebParser:CSVParser{// to do: add logic to get a stream from a web requestprotectedoverrideStreamGetStream(){thrownewNotImplementedException();}}publicclassPerson{publicStringName{get;set;}publicStringAddress{get;set;}publicDateTime DOB {get;set;}}publicclassPersonParser{publicPersonParser(CSVParser parser){this.Parser= parser;}publicCSVParserParser{get;set;}publicIEnumerable<Person>GetPersons(){foreach(String[] record inthis.Parser.GetRecords()){yieldreturnnewPerson(){Name= record[0],Address= record[1],
DOB =DateTime.Parse(record[2]),};}}}}
Uma boa maneira simples de fazer isso é abrir o arquivo e ler cada linha em um array, lista encadeada, estrutura de dados de sua escolha. No entanto, tenha cuidado ao manusear a primeira linha.
Isso pode passar por cima da sua cabeça, mas parece haver uma maneira direta de acessá-los usando uma string de conexão .
Por que não tentar usar Python em vez de C # ou VB? Tem um bom módulo CSV para importar que faz todo o trabalho pesado para você.
Não pule para python do VB por causa de um analisador CSV. Há um no VB. Embora estranhamente pareça ter sido ignorado nas respostas a esta pergunta. msdn.microsoft.com/en-us/library/…
MarkJ
1
Tive que usar um analisador CSV em .NET para um projeto neste verão e me conformei com o driver de texto Microsoft Jet. Você especifica uma pasta usando uma string de conexão e consulta um arquivo usando uma instrução SQL Select. Você pode especificar tipos fortes usando um arquivo schema.ini. Não fiz isso no início, mas depois estava obtendo resultados ruins em que o tipo de dados não era imediatamente aparente, como números de IP ou uma entrada como "XYQ 3.9 SP1".
Uma limitação que encontrei é que ele não pode lidar com nomes de colunas com mais de 64 caracteres; ele trunca. Isso não deve ser um problema, exceto que eu estava lidando com dados de entrada muito mal projetados. Ele retorna um ADO.NET DataSet.
Essa foi a melhor solução que encontrei. Eu desconfiaria de lançar meu próprio analisador CSV, já que provavelmente perderia alguns dos casos finais e não encontrei nenhum outro pacote de análise CSV gratuito para .NET por aí.
EDIT: Além disso, só pode haver um arquivo schema.ini por diretório, então eu anexei dinamicamente a ele para digitar fortemente as colunas necessárias. Ele só digitará fortemente as colunas especificadas e fará a inferência para qualquer campo não especificado. Eu realmente gostei disso, pois estava lidando com a importação de um CSV de coluna 70+ de fluido e não queria especificar cada coluna, apenas as que se comportavam mal.
Pode haver bibliotecas que você possa usar para ajudar, mas provavelmente é o mais simples possível. Apenas certifique-se de que não haja vírgulas nos dados, caso contrário, você precisará analisá-los melhor.
Respostas:
O TextFieldParser da Microsoft é estável e segue a RFC 4180 para arquivos CSV. Não desanime pelo
Microsoft.VisualBasic
namespace; é um componente padrão no .NET Framework, basta adicionar uma referência aoMicrosoft.VisualBasic
conjunto global .Se você está compilando para Windows (em oposição ao Mono) e não prevê ter que analisar arquivos CSV "quebrados" (não compatíveis com RFC), então esta seria a escolha óbvia, pois é gratuito, irrestrito, estável, e ativamente apoiado, a maioria dos quais não pode ser dito para FileHelpers.
Consulte também: How to: Read From Comma-Delimited Text Files in Visual Basic for a VB code example.
fonte
TextFieldParser
funcionará para delimitado por tabulação e outros dados estranhos gerados em Excel também. Eu percebo que a sua resposta anterior não estava afirmando que a biblioteca foi específico-VB, ele só veio até mim como implicando que foi realmente significou para VB, e não destina a ser usado em C #, que eu não acho que é o caso - existem algumas classes realmente úteis no MSVB.Use uma conexão OleDB.
fonte
Se você está esperando cenários bastante complexos para a análise CSV, nem pense em lançar nosso próprio analisador . Existem muitas ferramentas excelentes por aí, como FileHelpers , ou mesmo algumas do CodeProject .
A questão é que este é um problema bastante comum e você pode apostar que muitos desenvolvedores de software já pensaram e resolveram esse problema.
fonte
Brian oferece uma boa solução para convertê-lo em uma coleção fortemente tipada.
A maioria dos métodos de análise CSV fornecidos não leva em conta os campos de escape ou algumas das outras sutilezas dos arquivos CSV (como campos de corte). Aqui está o código que eu uso pessoalmente. É um pouco áspero nas bordas e praticamente não tem relatórios de erros.
Observe que isso não lida com o caso extremo de campos não serem delimitados por aspas duplas, mas apenas com uma string entre aspas. Veja este post para uma melhor expansão, bem como alguns links para algumas bibliotecas adequadas.
fonte
Eu concordo com @NotMyself . FileHelpers é bem testado e lida com todos os tipos de casos extremos com os quais você eventualmente terá que lidar se fizer isso sozinho. Dê uma olhada no que o FileHelpers faz e apenas escreva o seu próprio se você tiver certeza absoluta de que (1) você nunca precisará lidar com os casos extremos que o FileHelpers faz, ou (2) você adora escrever esse tipo de coisa e vai fique muito feliz quando tiver que analisar coisas como esta:
1, "Bill", "Smith", "Supervisor", "Sem comentários"
2, 'Drake,', 'O'Malley', "Zelador,
Ops, não fui citado e estou em uma nova linha!
fonte
Eu estava entediado, então modifiquei algumas coisas que escrevi. Ele tenta encapsular a análise de uma maneira OO enquanto corta a quantidade de iterações no arquivo, itera apenas uma vez no primeiro foreach.
fonte
Existem dois artigos sobre CodeProject que fornecem código para uma solução, um que usa StreamReader e outro que importa dados CSV usando o driver de texto da Microsoft .
fonte
Uma boa maneira simples de fazer isso é abrir o arquivo e ler cada linha em um array, lista encadeada, estrutura de dados de sua escolha. No entanto, tenha cuidado ao manusear a primeira linha.
Isso pode passar por cima da sua cabeça, mas parece haver uma maneira direta de acessá-los usando uma string de conexão .
Por que não tentar usar Python em vez de C # ou VB? Tem um bom módulo CSV para importar que faz todo o trabalho pesado para você.
fonte
Tive que usar um analisador CSV em .NET para um projeto neste verão e me conformei com o driver de texto Microsoft Jet. Você especifica uma pasta usando uma string de conexão e consulta um arquivo usando uma instrução SQL Select. Você pode especificar tipos fortes usando um arquivo schema.ini. Não fiz isso no início, mas depois estava obtendo resultados ruins em que o tipo de dados não era imediatamente aparente, como números de IP ou uma entrada como "XYQ 3.9 SP1".
Uma limitação que encontrei é que ele não pode lidar com nomes de colunas com mais de 64 caracteres; ele trunca. Isso não deve ser um problema, exceto que eu estava lidando com dados de entrada muito mal projetados. Ele retorna um ADO.NET DataSet.
Essa foi a melhor solução que encontrei. Eu desconfiaria de lançar meu próprio analisador CSV, já que provavelmente perderia alguns dos casos finais e não encontrei nenhum outro pacote de análise CSV gratuito para .NET por aí.
EDIT: Além disso, só pode haver um arquivo schema.ini por diretório, então eu anexei dinamicamente a ele para digitar fortemente as colunas necessárias. Ele só digitará fortemente as colunas especificadas e fará a inferência para qualquer campo não especificado. Eu realmente gostei disso, pois estava lidando com a importação de um CSV de coluna 70+ de fluido e não queria especificar cada coluna, apenas as que se comportavam mal.
fonte
Eu digitei algum código. O resultado no datagridviewer parecia bom. Ele analisa uma única linha de texto para uma lista de arraylist de objetos.
fonte
Se você pode garantir que não há vírgulas nos dados, a maneira mais simples provavelmente seria usar String.split .
Por exemplo:
Pode haver bibliotecas que você possa usar para ajudar, mas provavelmente é o mais simples possível. Apenas certifique-se de que não haja vírgulas nos dados, caso contrário, você precisará analisá-los melhor.
fonte