• 15 heures
  • Facile

Ce cours est visible gratuitement en ligne.

Ce cours est en vidéo.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

J'ai tout compris !

Mis à jour le 28/01/2019

Travaillez avec un fichier CSV

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Les fichiers, vous savez déjà ce que c'est : fichier word (docx), texte (txt), image (jpg). Il existe des centaines de formats de fichiers. Parmi ces formats, Il existe un type de fichier très simple, souvent utilisé pour stocker des données : le format CSV.

Pour récupérer une version propre du projet prêt pour ce chapitre, vous pouvez importer le projet git suivant : MyMenu - Step 9.

Comma-separated values

Un fichier CSV ou Comma-Separated Values est un simple fichier texte dans lequel on sauvegarde des données. Celles-ci sont séparées par des virgules, et des retours à la ligne. Le fichier porte l'extention .csv.

Voici un exemple de contenu de fichier CSV :

nom,age,ville
Alexis,18,Paris
Vincent,31,Bordeaux
Maevan,26,Marseille
Jean,54,Lyon

Ce fichier peut servir à stocker :

  • les personnes interrogées dans le cadre d'une étude ;

  • les clients d'un magasin ;

  • les produits disponibles dans un catalogue ;

  • les films à l'affiche d'un cinéma ;

  • etc.

On peut mettre tout et n'importe quoi dans un fichier csv. Le fichier commence en mettant sur la première ligne les titres de chaque information. Puis, en suivant sur chaque ligne, les informations voulues (en veillant à respecter l'ordre des titres).

Dans notre cas, nous allons utiliser notre fichier pour sauvegarder l'ensemble des commandes de notre menu interactif.

Votre premier fichier CSV

À quoi ce fichier va ressembler ? On va se contenter d'un format simple.

menu,accompagnement,boisson
2,1,1
1,2,1
3,2,2

Pour chaque ligne on a :

  • le numéro du menu ;

  • le numéro de l'accompagnement ;

  • le numéro de la boisson (-1 s'il n'y en a pas).

Java est composé de centaines d'outils. Avec un de ces outils on peut ouvrir, lire et écrire dans un fichier.

Pour écrire dans un fichier, il faut créer une variable de type Path contenant le chemin vers votre fichier.

jshell> Path orderPath = Paths.get("order.csv");
orderPath ==> order.csv

On va maintenant créer notre fichier et écrire dedans.

jshell> Files.write(orderPath, String.format("menu,accompagnement,boisson%n").getBytes());
$6 ==> order.csv

Si je regarde le contenu du dossier dans lequel j'ai lancé JShell, il y a bien un fichier test.csv contenant menu,accompagnement,boisson :

~ > cat order.csv
menu,accompagnement,boisson

Utilisons ces outils pour créer le fichier order.csv avec notre application.

Quelques indices pour une solution propre :

  • cette fois-ci pas besoin d'attribut ;

  • on va créer le  Path  dans runMenus ;

  • askSide  et  askDrink  doivent eux aussi retourner le numéro du choix ;

  • avec ça, il reste à utiliser  Files.write  à la fin de  runMenus.

On commence à entrer dans des fonctionnalités avancées de Java. Pour pouvoir tester l'écriture dans un fichier proprement, il faudrait utiliser de l'injection et des mocks. Le cours sur les tests unitaires explique ces principes.

Par défaut  Files.write  écrase votre fichier. Pour ne pas écraser le fichier, mais pour y ajouter du contenu, il faut donner un paramètre supplémentaire à  Files.write  :

Files.write(orderPath, orderLine.getBytes(), APPEND);

Voici le code modifié :

package com.ocr.anthony;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.InputMismatchException;
import java.util.Scanner;

import static java.nio.file.StandardOpenOption.APPEND;

public class Order {
    
    ...
    
    /**
     * Run asking process for a menu.
     */
    public String runMenu() {
        int nbMenu = askMenu();
        int nbSide = -1;
        int nbDrink = -1;
        switch (nbMenu) {
            case 1:
                nbSide = askSide(true);
                nbDrink = askDrink();
                break;
            case 2:
                nbSide = askSide(true);
                break;
            case 3:
                nbSide = askSide(false);
                nbDrink = askDrink();
                break;
        }
        return nbMenu + "," + nbSide + "," + nbDrink + "%n";
    }
    
    /**
     * Run asking process for several menus.
     */
    public void runMenus() {
        Path orderPath = Paths.get("order.csv");
        System.out.println("Combien souhaitez vous commander de menu ?");
        int menuQuantity = -1;
        boolean responseIsGood;
        do {
            try {
                menuQuantity = sc.nextInt();
                responseIsGood = true;
            } catch (InputMismatchException e) {
                sc.next();
                System.out.println("Vous devez saisir un nombre, correspondant au nombre de menus souhaités");
                responseIsGood = false;
            }
        } while (!responseIsGood);
        orderSummary = "Résumé de votre commande :%n";
        for (int i = 0; i < menuQuantity; i++) {
            orderSummary += "Menu " + (i + 1) + ":%n";
            String orderLine = runMenu();
            Files.write(orderPath, String.format(orderLine).getBytes(), APPEND);
        }
        System.out.println("");
        System.out.println(String.format(orderSummary));
    }
    
    ...
    
    /**
     * Display a question about side in the standard input, get response and display it
     * @param allSidesEnable
     * @return chosen value
     */
    public int askSide(boolean allSidesEnable) {
        if (allSidesEnable) {
            String[] responsesAllSide = {"légumes frais", "frites", "riz"};
            return askSomething("accompagnement", responsesAllSide);
        } else {
            String[] responsesOnlyRice = {"riz", "pas de riz"};
            return askSomething("accompagnement", responsesOnlyRice);
        }
    }
    
    /**
     * Display a question about drink in the standard input, get response and display it
     * @return chosen value
     */
    public int askDrink() {
        String[] responsesDrink = {"eau plate", "eau gazeuse", "soda"};
        return askSomething("boisson", responsesDrink);
    }
}

 Si on en reste là, IntelliJ souligne la ligne  Files.write . C'est une erreur qui empêche la compilation. L'erreur est la suivante :  Unhandled exception: java.io.IOException

C'est une des exceptions que vous êtes obligé de catcher. Cette erreur peut intervenir si le fichier est bloqué en écriture par exemple.

Cliquez sur la petite ampoule rouge puis sur Surround with try/catch.

Génération try/catch
Génération try/catch

Le code suivant est généré automatiquement :

try {
    Files.write(orderPath, String.format(orderLine).getBytes(), APPEND);
} catch (IOException e) {
    e.printStackTrace();
}

e.printStrackTrace()  sert à afficher dans la console une erreur contenant beaucoup d'informations pour aider au debug :

java.nio.file.AccessDeniedException: order.csv
    at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:90)
    at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
    at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:116)
    at java.base/sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:215)
    at java.base/java.nio.file.spi.FileSystemProvider.newOutputStream(FileSystemProvider.java:434)
    at java.base/java.nio.file.Files.newOutputStream(Files.java:218)
    at java.base/java.nio.file.Files.write(Files.java:3352)
    at com.ocr.anthony.Main.main(Main.java:82)

Ce n'est pas super d'afficher ce texte à l'utilisateur. C'est mieux comme ceci :

try {
    Files.write(orderPath, String.format(orderLine).getBytes(), APPEND);
} catch (IOException e) {
    System.out.println("Ooops une erreur est survenue. Merci de réessayer plus tard");
    return;
}

return; utilisé seul, sert à sortir de la méthode (et donc quitter le programme).

Vous pouvez créer le fichier order.csv à la racine de votre projet en faisant clic droit sur MyMenuOCR > New > File.

Nouveau fichier csv
Nouveau fichier .csv
Fichier nommé order.csv
Fichier nommé order.csv

Pensez à ajouter les titres à la première ligne et une ligne vide.

menu,accompagnement,boisson

Lisez du CSV

On va maintenant coder un second programme qui va lire notre fichier CSV. Dans ce programme, on va ouvrir le fichier order.csv puis afficher l'ensemble des commandes inscrites à l'intérieur.

Pour lire un fichier CSV il faut faire :

jshell> List<String> lines = Files.readAllLines(orderPath);
lines ==> [menu,accompagnement,boisson, 1,2,3, 2,3,-1, 3,2,2]

jshell> for (int i = 1; i < lines.size(); i++) {
   ...> System.out.println(lines.get(i));
   ...> }
1,2,3
2,3,-1
3,2,2

jshell> lines.get(2).split(",");
$20 ==> String[3] { "2", "3", "-1" }

jshell> lines.get(2).split(",")[2];
$21 ==> "-1"

Nous allons procéder de la façon suivante :

  • Ajoutez une nouvelle classe dédiée : clic droit sur le package contenant votre  Main  (chez moi com.ocr.anthony), puis New > Java Class . Nommez-la OrderReader .

  • Dans ce fichier, saisissez psvm puis , cela va automatiquement créer une nouvelle méthode  main .

  • Créez une méthode  read .

  • Créez une variable  Path  vers le fichier order.csv .

  • Ignorez la première ligne du fichier (les titres).

  • Pour chaque ligne du fichier, affichez le détail de la commande.

  • Enfin dans le  main , utilisez  read.

Voici le code :

package com.ocr.anthony;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

public class OrderReader {
    public void read() {
        Path orderPath = Paths.get("order.csv");
        List<String> lines = null; //null mean no value by default
        try {
            lines = Files.readAllLines(orderPath);
        } catch (IOException e) {
            System.out.println("Impossible de lire le fichier des commandes");
        }
        if (lines.size() < 2) {
            System.out.println("Il n'y a pas de commande dans le fichier");
            return;
        }
        String[] menus = {"Menu Poulet", "Menu Boeuf", "Menu Végétarien"};
        String[] side = {" avec des légumes frais", " avec des frites", " avec du riz"};
        String[] sideVegetarian = {" avec du riz", " sans riz"};
        String[] drink = {" et avec de l'eau plate", " et avec de l'eau gazeuse", " et avec du soda"};

        for (int i = 1; i < lines.size(); i++) {
            String[] split = lines.get(i).split(",");
            int nbMenu = Integer.valueOf(split[0]);
            int nbSide = Integer.valueOf(split[1]);
            int nbDrink = Integer.valueOf(split[2]);
            String orderLine = menus[nbMenu - 1];
            if (nbMenu == 3) //vegetarian menu
                orderLine += sideVegetarian[nbSide - 1];
            else
                orderLine += side[nbSide - 1];
            if (nbDrink == -1)
                orderLine += " et sans boisson";
            else
                orderLine += drink[nbDrink - 1];
            System.out.println(orderLine);
        }
    }

    public static void main(String[] args) {
        OrderReader orderReader = new OrderReader();
        orderReader.read();
    }
}

Vous pouvez exécuter ce programme en cliquant sur le triangle vert à côté de main.

Que signifient  //null mean no value by default  et  //vegetarian menu  ?

Ce sont des commentaires. Ils ne changent pas le comportement du programme. C'est une aide pour vous et les autres développeurs.

Attention à ne pas en abuser. Un code bien nommé et aéré sera toujours plus compréhensible que des commentaires.

Nous avons fini avec ce chapitre. Dans le prochain et dernier chapitre, nous verrons ce que sont les libraries et les frameworks et comment les utiliser. 

Exemple de certificat de réussite
Exemple de certificat de réussite