Ler CSV com Scanner ()

Meu csv está sendo lido no System.out, mas notei que qualquer texto com um espaço é movido para a próxima linha (como um retorno \ n)

Aqui está como meu csv começa:

first,last,email,address 1, address 2 john,smith,blah@blah.com,123 St. Street, Jane,Smith,blech@blech.com,4455 Roger Cir,apt 2 

Depois de executar meu aplicativo, qualquer célula com espaço (endereço 1) é lançada na próxima linha.

 import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; public class main { public static void main(String[] args) { // -define .csv file in app String fileNameDefined = "uploadedcsv/employees.csv"; // -File class needed to turn stringName to actual file File file = new File(fileNameDefined); try{ // -read from filePooped with Scanner class Scanner inputStream = new Scanner(file); // hashNext() loops line-by-line while(inputStream.hasNext()){ //read single line, put in string String data = inputStream.next(); System.out.println(data + "***"); } // after loop, close scanner inputStream.close(); }catch (FileNotFoundException e){ e.printStackTrace(); } } } 

Então aqui está o resultado no console:

 primeiro, último, email, endereço 
 1, endereço 
 2
 john, smith, blah @ blah.com, 123 
 St. 
 Rua,
 Jane, Smith, blech @ blech.com, 4455 
 Roger 
 Cir, apt 
 2

Estou usando o scanner incorretamente?

 scanner.useDelimiter(","); 

Isso deve funcionar.

 import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; public class TestScanner { public static void main(String[] args) throws FileNotFoundException { Scanner scanner = new Scanner(new File("/Users/pankaj/abc.csv")); scanner.useDelimiter(","); while(scanner.hasNext()){ System.out.print(scanner.next()+"|"); } scanner.close(); } } 

Para o arquivo CSV:

 a,b,cd,e 1,2,3 4,5 X,Y,ZA,B 

A saída é:

 a|b|cd|e 1|2|3 4|5 X|Y|ZA|B| 

Por favor, pare de escrever parsers CSV com defeito!

Eu vi centenas de analisadores de CSV e os chamados tutoriais online.

Quase todos eles entendem errado!

Isso não seria uma coisa tão ruim, pois não me afeta, mas as pessoas que tentam escrever os leitores de CSV e se enganam tendem a escrever escritores de CSV também. E entenda errado também. E esses eu tenho que escrever parsers para.

Por favor, tenha em mente que CSV (em ordem de aumentar não tão óbvio):

  1. pode ter citando caracteres em torno de valores
  2. pode ter outros caracteres de citação do que ”
  3. pode até ter outros caracteres de citação do que “e”
  4. não pode ter caracteres de citação em tudo
  5. pode até ter citando caracteres em alguns valores e nenhum em outros
  6. pode ter outros separadores, e;
  7. pode ter espaço em branco entre os operadores e valores (citados)
  8. pode ter outros charsets que ascii
  9. deve ter o mesmo número de valores em cada linha, mas nem sempre
  10. pode conter campos vazios, citados: "foo","","bar" ou não: "foo",,"bar"
  11. pode conter novas linhas em valores
  12. não pode conter novas linhas em valores se eles não forem delimitados
  13. não pode conter novas linhas entre valores
  14. pode ter o caractere delimitador dentro do valor se tiver escapado adequadamente
  15. não usa barras invertidas para escaping de delimitadores, mas …
  16. usa o próprio caractere de citação para escaping dele, por exemplo, Frodo's Ring será 'Frodo''s Ring'
  17. pode ter o caractere de aspas no início ou no final do valor, ou mesmo como apenas caractere ( "foo""", """bar", """" )
  18. pode até ter o caractere entre aspas dentro do valor não citado; este não é escapado

Se você acha que isso é óbvio não é um problema, então pense novamente. Eu vi cada um desses itens implementados de forma errada. Mesmo em grandes pacotes de software. (por exemplo, Office-Suites, CRM Systems)

Há bons e corretamente trabalhando leitores e escritores CSV out-of-the-box por aí:

  • opencsv
  • Ostermiller Java Utilities

Se você insistir em escrever o seu próprio, leia pelo menos (muito curto) RFC para CSV .

Scanner.next() não lê uma nova linha, mas lê o próximo token, delimitado por espaço em branco (por padrão, se useDelimiter() não foi usado para alterar o padrão do delimitador). Para ler uma linha, use Scanner.nextLine() .

Depois de ler uma única linha, você pode usar String.split(",") para separar a linha em campos. Isso permite a identificação de linhas que não consistem no número necessário de campos. Usando useDelimiter(","); ignoraria a estrutura baseada em linha do arquivo (cada linha consiste em uma lista de campos separados por uma vírgula). Por exemplo:

 while (inputStream.hasNextLine()) { String line = inputStream.nextLine(); String[] fields = line.split(","); if (fields.length >= 4) // At least one address specified. { for (String field: fields) System.out.print(field + "|"); System.out.println(); } else { System.err.println("Invalid record: " + line); } } 

Como já mencionado, o uso de uma biblioteca CSV é recomendado. Por um lado, essa (e a useDelimiter(",") ) não manipulará corretamente os identificadores entre aspas contendo caracteres.

Se você absolutamente deve usar o Scanner, então você deve definir seu delimitador através de seu useDelimiter(...) . Senão, o padrão será usar todo o espaço em branco como seu delimitador. Melhor ainda, como já foi dito – use uma biblioteca CSV, já que é isso que eles fazem melhor.

Por exemplo, esse delimitador será dividido em vírgulas com ou sem espaço em branco adjacente:

 scanner.useDelimiter("\\s*,\\s*"); 

Por favor, confira a API java.util.Scanner para saber mais sobre isso.

Dividir nextLine () por este delimitador – (? = ([^ \ “] \” [^ \ “] \”) [^ \ “] $)”) Para um array.

Ele lida com seu problema

Eu concordo com Scheintod que usar uma biblioteca CSV existente é uma boa idéia ter compatibilidade com a RFC-4180 desde o início. Além dos mencionados OpenCSV e Oster Miller, há uma série de outras bibliotecas CSV por aí. Se você estiver interessado em desempenho, você pode dar uma olhada na comparação uniVocity / csv-parsers . Isso mostra que

  • analisador de CSV uniVocity
  • Analisador CSV SimpleFlatMapper
  • Analisador CSV Jackson

são consistentemente os mais rápidos usando JDK 6, 7, 8 ou 9. O estudo não encontrou nenhum problema de compatibilidade com a RFC 4180 em nenhum desses três. Tanto o OpenCSV quanto o Oster Miller são aproximadamente duas vezes mais lentos que esses.

Não estou de forma alguma associado ao (s) autor (es), mas no que diz respeito ao analisador de CSV uniVocity, o estudo pode ser tendencioso devido ao fato de seu autor ser o mesmo daquele analisador.

Para notar, o autor do SimpleFlatMapper também publicou uma comparação de desempenho comparando apenas os três.

Bem, eu faço minha codificação no NetBeans 8.1:

Primeiro: crie um novo projeto, selecione o aplicativo Java e nomeie seu projeto.

Em seguida, modifique seu código após a class pública para se parecer com o seguinte:

 /** * @param args the command line arguments * @throws java.io.FileNotFoundException */ public static void main(String[] args) throws FileNotFoundException { try (Scanner scanner = new Scanner(new File("C:\\Users\\YourName\\Folder\\file.csv"))) { scanner.useDelimiter(","); while(scanner.hasNext()){ System.out.print(scanner.next()+"|"); }} } }