Lire CSV avec Scanner()

Mon csv est lu dans le système.out, mais j'ai remarqué que tout texte avec un espace est déplacé dans la ligne suivante (comme un retour n)

Voici comment mon csv commence:

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

Après avoir exécuté mon application, toute cellule avec un espace (Adresse 1) est jeté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();
        }

    }
}

Voici donc le résultat dans la console:

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

Est - ce que J'utilise le Scanner de manière incorrecte?

37
demandé sur feeling abused and harassed 2013-01-11 12:28:44

7 réponses

scanner.useDelimiter(",");

Cela devrait fonctionner.

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|
34
répondu Pankaj 2013-01-11 08:47:53

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

J'ai vu des centaines D'analyseurs CSV et soi-disant tutoriels pour eux en ligne.

Presque chacun d'entre eux se trompe!

, Ce ne serait pas une si mauvaise chose que ça n'affecte pas moi, mais les gens qui essaient d'écrire CSV lecteurs et se tromper tendance à écrire CSV écrivains, trop. Et de les faire de mal que de bien. Et ceux-ci pour lesquels je dois écrire des analyseurs.

, Veuillez garder à l'esprit que CSV (par ordre croissant pas si évident):

  1. peut avoir des caractères de citation autour des valeurs
  2. peut avoir d'autres caractères de citation que "
  3. peut même avoir d'autres caractères de citation 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 (entre guillemets)
  8. peut avoir autres jeux de caractères que ascii
  9. devrait avoir le même nombre de valeurs dans chaque ligne, mais pas toujours
  10. peut contenir des champs vides, entre guillemets: "foo","","bar" ou non: "foo",,"bar"
  11. peut contenir des retours à la ligne dans les valeurs
  12. ne peut pas contenir des nouvelles lignes dans les valeurs si elles ne sont pas délimitées
  13. ne peut pas contenir des sauts de ligne entre les valeurs
  14. peut avoir le caractère délimitant dans la valeur s'il est correctement échappé
  15. fait pas utiliser backslash pour échapper délimiteurs mais...
  16. utilise le caractère de citation lui-même pour l'échapper, par exemple {[2] } 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 entre guillemets dans la valeur non entre guillemets; celui-ci est pas échappé

Si vous pensez que cela est évident pas un problème, alors détrompez-vous. J'ai vu chacun de ces éléments mis en œuvre à tort. Même dans les logiciels majeurs . (par exemple, les suites bureautiques, les systèmes CRM)

Il existe de bons lecteurs et écrivains CSV prêts à l'emploi:

Si vous insistez pour écrire le vôtre, lisez au moins le (très court) RFC pour CSV .

117
répondu Scheintod 2017-03-16 08:48:47

Scanner.next() ne lit pas de nouvelle ligne mais lit le jeton suivant, délimité par des espaces (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 sont pas constituées du nombre requis de champs. L'utilisation de useDelimiter(","); ignorerait la structure en ligne du fichier (chaque ligne consiste en une liste de champs séparés par une virgule). Pour 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, cette solution (et useDelimiter(",")) ne gérera pas correctement les identifiants entre guillemets contenant des caractères ,.

7
répondu hmjd 2013-01-11 08:46:10

Je suis d'accord avec Scheintod que l'utilisation d'une bibliothèque CSV existante est une bonne idée d'avoir la conformité RFC-4180 dès le début. Outre les opencsv et Oster Miller mentionnés, il existe une série d'autres bibliothèques CSV. Si vous êtes intéressé par les performances, vous pouvez jeter un oeil à la uniVocity/csv-parsers-comparison. Il montre que

Sont toujours les plus rapides en utilisant JDK 6, 7, 8 ou 9. L'étude n'a trouvé aucun problème de compatibilité RFC 4180 dans l'un de ces trois. OpenCSV et Oster Miller sont deux fois plus lents que ceux-ci.

Je ne suis en aucune façon associé au(X) auteur (s), mais en ce qui concerne l'analyseur csv uniVocity, l'étude pourrait être biaisée en raison du fait que son auteur est le même que celui de cet analyseur.

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

1
répondu Yushin Washio 2018-07-05 10:10:37

Diviser nextLine() par ce délimiteur - (?=([^\"]\"[^\"]\")[^\"]$)") pour un tableau.

Il gère votre problème

0
répondu Harsh Mighlani 2018-03-08 10:18:11

Si vous devez absolument utiliser Scanner, vous devez définir son délimiteur via sa méthode useDelimiter(...). Sinon, il utilisera par défaut tous les espaces blancs comme délimiteur. Mieux encore, comme cela a déjà été dit-utilisez une bibliothèque CSV car c'est ce qu'ils font le mieux.

Par exemple, ce délimiteur sera divisé sur des virgules Avec ou sans espaces environnants:

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

Veuillez consulter le java.util.API du Scanner pour en savoir plus.

-1
répondu Hovercraft Full Of Eels 2013-01-11 08:38:26

Eh bien, je fais mon codage dans NetBeans 8.1:

Tout d'abord: créez un nouveau projet, sélectionnez Application Java et nommez votre projet.

Puis modifiez votre code après la classe publique pour ressembler à ce qui suit:

/**
 * @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()+"|");
         }}
    }
}
-2
répondu Panther859 2016-01-23 15:16:04