Leggi CSV con Scanner ()

Il mio CSV viene letto nel System.out, ma ho notato che qualsiasi testo con uno spazio viene spostato nella riga successiva (come un ritorno \ n)

Ecco come inizia il mio CSV:

first,last,email,address 1, address 2 john,smith,[email protected],123 St. Street, Jane,Smith,[email protected],4455 Roger Cir,apt 2 

Dopo aver eseguito la mia app, qualsiasi cella con uno spazio (indirizzo 1), viene lanciata sulla riga successiva.

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

Quindi, ecco il risultato nella console:

 primo, ultimo, e-mail, indirizzo 
 1, l'indirizzo 
 2
 John, Smith, bla @ blah.com, 123 
 St. 
 Strada,
 Jane, Smith, blech @ blech.com, 4455 
 Roger 
 Cir, apt 
 2

Sto utilizzando lo scanner in modo errato?

 scanner.useDelimiter(","); 

Questo dovrebbe funzionare.

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

Per file CSV:

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

L’output è:

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

Si prega di smettere di scrivere parser CSV difettosi!

Ho visto centinaia di parser CSV e tutorial cosiddetti per loro online.

Quasi tutti sbagliano!

Questo non sarebbe così male come non mi riguarda, ma le persone che provano a scrivere lettori CSV e sbagliano tendono a scrivere anche scrittori CSV. E sbaglia anche loro. E questi per i quali devo scrivere parser.

Si prega di tenere presente che CSV (in ordine crescente non è così ovvio):

  1. può avere la citazione di caratteri attorno ai valori
  2. può avere altri caratteri di citazione che ”
  3. può anche avere altri caratteri che citano “e”
  4. non può avere alcun carattere di citazione
  5. può anche avere caratteri di quotatura su alcuni valori e nessuno su altri
  6. può avere altri separatori di, e;
  7. può avere spazi bianchi tra separatori e valori (quotati)
  8. può avere altri set di caratteri che ascii
  9. dovrebbe avere lo stesso numero di valori in ogni riga, ma non sempre
  10. può contenere campi vuoti, o quotati: "foo","","bar" o non: "foo",,"bar"
  11. può contenere newline in valori
  12. non può contenere newline in valori se non sono delimitati
  13. non può contenere una nuova riga tra i valori
  14. può avere il carattere di delimitazione all’interno del valore se opportunamente sfuggito
  15. non usa il backslash per sfuggire ai delimitatori ma …
  16. usa il carattere quotante stesso per sfuggire ad esso, ad esempio Frodo's Ring sarà 'Frodo''s Ring'
  17. può avere il carattere quotante all’inizio o alla fine del valore, o anche solo come carattere ( "foo""", """bar", """" )
  18. può anche avere il carattere quotato all’interno del valore non quotato; questo non è sfuggito

Se pensi che questo sia ovvio, non è un problema, quindi ripensaci. Ho visto ognuno di questi elementi implementati in modo errato. Anche nei principali pacchetti software. (ad es. Office-Suites, sistemi CRM)

Là fuori ci sono lettori e scrittori di CSV pronti e correttamente funzionanti:

  • opencsv
  • Ostermiller Java Utilities

Se insisti a scrivere la tua, leggi almeno la (molto breve) RFC per CSV .

Scanner.next() non legge una nuova riga ma legge il token successivo, delimitato da spazi bianchi (per impostazione predefinita, se useDelimiter() non è stato utilizzato per modificare il pattern delimitatore). Per leggere una riga, utilizzare Scanner.nextLine() .

Una volta che hai letto una singola riga, puoi usare String.split(",") per separare la linea in campi. Ciò consente l’identificazione di linee che non consistono nel numero richiesto di campi. Using useDelimiter(","); ignorerebbe la struttura a riga del file (ogni riga consiste in un elenco di campi separati da una virgola). Per esempio:

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

Come già accennato, si consiglia di utilizzare una libreria CSV. Per uno, questa (e useDelimiter(",") soluzione) non gestirà correttamente gli identificatori quotati contenenti caratteri.

Se è assolutamente necessario utilizzare Scanner, è necessario impostarne il delimitatore tramite il useDelimiter(...) . Altrimenti, per impostazione predefinita utilizzerà tutto lo spazio bianco come delimitatore. Meglio però come è già stato detto: usa una libreria CSV poiché è ciò che fanno meglio.

Ad esempio, questo delimitatore verrà diviso in virgole con o senza spazi vuoti circostanti:

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

Si prega di controllare l’ API java.util.Scanner per ulteriori informazioni.

Dividi nextline () di questo delimitatore – (? = ([^ \ “] \” [^ \ “] \”) [^ \ “] $)”) In un array.

Gestisce il tuo problema

Sono d’accordo con Scheintod che usare una libreria CSV esistente è una buona idea avere la conformità RFC-4180 sin dall’inizio. Oltre al citato OpenCSV e Oster Miller, ci sono una serie di altre librerie CSV là fuori. Se sei interessato alle prestazioni, puoi dare un’occhiata a uniVocity / csv-parsers-comparison . Lo dimostra

  • parser CSV uniVocity
  • Parser CSV SimpleFlatMapper
  • Parser CSV Jackson

sono costantemente i più veloci utilizzando JDK 6, 7, 8 o 9. Lo studio non ha riscontrato problemi di compatibilità con RFC 4180 in nessuno di questi tre. Sia OpenCSV che Oster Miller risultano essere due volte più lenti di quelli.

Non sono in alcun modo associato con l’autore (s), ma riguardo al parser CSV uniVocity, lo studio potrebbe essere di parte dovuto al fatto che il suo autore è lo stesso di quello parser.

Da notare, l’autore di SimpleFlatMapper ha anche pubblicato un confronto delle prestazioni confrontando solo questi tre.

Bene, faccio la mia codifica in NetBeans 8.1:

Primo: crea un nuovo progetto, seleziona l’applicazione Java e assegna un nome al tuo progetto.

Quindi modifica il tuo codice dopo la public class per assomigliare al seguente:

 /** * @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()+"|"); }} } }