web-dev-qa-db-fra.com

Lire un fichier CSV avec un scanner ()

Mon csv est lu dans le fichier System.out, mais j’ai remarqué que tout texte avec un espace était déplacé dans la ligne suivante (en tant que retour\n)

Voici comment mon csv commence:

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

Après avoir exécuté mon application, toute cellule avec un espace (adresse 1) est projetée sur la ligne suivante.

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

    }
}

Alors voici le résultat dans la console:

 premier, dernier, email, adresse 
 1, adresse 
 2 
 john, smith, blah @ blah.com, 123 
 St. 
 Street, 
 Jane, Smith, blech @ blech.com, 4455 
 Roger 
 Cir, apt 
 2 

Est-ce que j'utilise mal le scanner?

39
coffeemonitor
scanner.useDelimiter(",");

Cela devrait marcher.

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

}

Pour le fichier CSV:

a,b,c d,e
1,2,3 4,5
X,Y,Z A,B

La sortie est:

a|b|c d|e
1|2|3 4|5
X|Y|Z A|B|
39
Pankaj

Veuillez arrêter d'écrire des analyseurs syntaxiques CSV défectueux!

J'ai vu des centaines de parseurs CSV et ce qu'on appelle tutorials pour eux en ligne.

Presque chacun d'entre eux se trompe! 

Cela ne serait pas une si mauvaise chose car cela ne me concerne pas, mais ceux qui essaient d'écrire CSV lecteurs et se trompent ont tendance à écrire CSV écrivains aussi. Et comprenez-les aussi. Et ceux-ci, je dois écrire des analyseurs syntaxiques.

S'il vous plaît gardez à l'esprit que CSV (dans l'ordre croissant pas si évident):

  1. peut avoir des caractères de citation autour des valeurs
  2. peut avoir d'autres caractères que "
  3. peut même avoir des caractères de citation autres que "et"
  4. ne peut avoir aucun caractère de citation
  5. peut même avoir des caractères de citation sur certaines valeurs et aucun sur d'autres
  6. peut avoir d'autres séparateurs que, et;
  7. peut avoir des espaces entre les séparateurs et les valeurs (citées)
  8. peut avoir d'autres jeux de caractères que l'asci
  9. devrait avoir le même nombre de valeurs dans chaque ligne, mais pas toujours
  10. peut contenir des champs vides, cités: "foo","","bar" ou non: "foo",,"bar"
  11. peut contenir des nouvelles lignes dans les valeurs
  12. ne peut pas contenir de nouvelles lignes dans les valeurs si elles ne sont pas délimitées
  13. ne peut pas contenir de nouvelles lignes entre les valeurs
  14. peut avoir le caractère de délimitation dans la valeur s'il est correctement échappé
  15. n'utilise pas de barre oblique inverse pour échapper aux délimiteurs mais ...
  16. utilise le caractère de citation lui-même pour y échapper, par ex. Frodo's Ring sera 'Frodo''s Ring'
  17. peut avoir le caractère de citation au début ou à la fin de la valeur, ou même comme seul caractère ("foo""", """bar", """")
  18. peut même avoir le caractère cité dans la valeur non citée; celui-ci est pas échappé

Si vous pensez que ce n'est pas un problème évident, alors détrompez-vous. J'ai vu chacun des de ces éléments mal implémentés. Même dans les principaux progiciels. (par exemple, suites bureautiques, systèmes CRM)

Il existe de bons lecteurs et rédacteurs CSV prêts à l'emploi qui fonctionnent correctement:

Si vous insistez pour écrire vous-même, lisez au moins le (très court) RFC for CSV .

133
Scheintod

Scanner.next() ne lit pas de nouvelle ligne mais lit le prochain jeton, délimité par un espace (par défaut, si useDelimiter() n'a pas été utilisé pour changer le motif de délimiteur) Pour lire une ligne, utilisez Scanner.nextLine().

Une fois que vous avez lu une seule ligne, vous pouvez utiliser String.split(",") pour séparer la ligne en champs. Cela permet d'identifier les lignes qui ne comprennent pas le nombre de champs requis. Utiliser useDelimiter(","); ignorerait la structure du fichier basée sur les lignes (chaque ligne consiste en une liste de champs séparés par une virgule). Par exemple:

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

Comme déjà mentionné, l'utilisation d'une bibliothèque CSV est recommandée. D'une part, cela (et la solution useDelimiter(",")) ne gérera pas correctement les identificateurs entre guillemets contenant des caractères ,.

8
hmjd

Je suis d'accord avec Scheintod pour dire que l'utilisation d'une bibliothèque CSV existante est une bonne idée d'avoir la conformité à la RFC-4180 dès le début. Outre OpenCSV et Oster Miller, il existe une série d'autres bibliothèques CSV. Si les performances vous intéressent, vous pouvez jeter un oeil à uniVocity/csv-parsers-compare . Cela montre que

sont systématiquement les plus rapides en utilisant JDK 6, 7, 8 ou 9. L’étude n’a révélé aucun problème de compatibilité RFC 4180 dans l’un de ces trois problèmes. OpenCSV et Oster Miller sont environ deux fois plus lents que ceux-ci.

Je ne suis en aucun cas associé au (x) auteur (s), mais en ce qui concerne l’analyseur uniVocity CSV, l’étude peut être biaisée car son auteur est identique à celui de cet analyseur.

À noter, l'auteur de SimpleFlatMapper a également publié un performance performance comparant seulement ces trois.

1
Yushin Washio

Fractionnez nextLine () par ce délimiteur: (?=([^\"]*\"[^\"]*\")*[^\"]*$)").

0
Harsh Mighlani