Charger des données depuis un fichier CSV simple en 5 minutes
Date de publication : 26 janvier 2012. Date de mise à jour : 27 février 2012.
Par
Thierry Leriche-Dessirier 
Ce petit article montre (par l'exemple) comment charger des données depuis un fichier CSV simple, à l'aide d'Open-CSV, en quelques minutes.
11 commentaires
1. Introduction
1-A. À propos
1-B. Avant de commencer
1-C. Mise-à-jour
2. Découverte du modèle d'exemple
2-A. Télécharger, installer et importer le projet d'exemple
2-B. Les objets du modèle
2-C. Les données à lire
3. Action
3-A. Compléter le modèle
3-B. Créer des DAO vides
3-C. Ajout d'Open-CSV
3-D. Lecture des données
4. Conclusions
5. Remerciements
6. Annexes
6-A. Liens
6-B. Les fichiers importants en entier
6-C. Utilisation de la lib MoteurCsv
1. Introduction
Dans ce document, nous allons voir comment charger des données depuis un fichier CSV simple à l'aide de la bibliothèque
Open-CSV, puis transformer ces données en objets de notre modèle.
 | Open-CSV est une bibliothèque gratuite, écrite en Java, qui simplifie la lecture complexe des fichiers CSV. |
1-A. À propos
Découvrir une technologie n'est pas chose facile. En aborder plusieurs d'un coup l'est encore moins. Partant de ce constat, cet article a été écrit pour aller à l'essentiel. Les points importants sont présentés dans le corps de l'article et les éléments secondaires sont expliqués en annexe.
1-B. Avant de commencer
Pour écrire ce tutoriel, j'ai utilisé les éléments suivants :
- Java JDK 1.6.0_24-b07 ;
- Eclipse Indigo 3.7 JEE 64b ;
- Maven 3.0.3.
1-C. Mise-à-jour
27 février 2012 : Ajout d'un exemple d'utilisation de la lib MoteurCsv en annexe.
2. Découverte du modèle d'exemple
2-A. Télécharger, installer et importer le projet d'exemple
 | Pour suivre ce tutoriel, vous pouvez vous contenter de lire les codes proposés ci-dessous (codes complets en annexe). |
2-B. Les objets du modèle
Le projet d'exemple reprend les objets utilisés dans les tutoriels cités plus haut, et dont l'objectif est de modéliser (et d'afficher) les notes d'un groupe d'élèves au dernier examen.
Sans ordre, le modèle est composé des objets suivants.
| Sexe.java |
package com.thi.notes.domain;
public enum Sexe {
HOMME("Garçon"),
FEMME("Fille");
private final String label;
Sexe(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
}
|
| Eleve.java |
package com.thi.notes.domain;
public class Eleve {
private String nom;
private String prenom;
private Integer annee;
private Sexe sexe;
public Eleve(String nom, String prenom, Integer annee, Sexe sexe) {
...
}
}
|
| NoteEleve.java |
package com.thi.notes.domain;
public class NoteEleve {
private Eleve eleve;
private Double note;
public NoteEleve(Eleve eleve, Double note) {
...
}
}
|
Sans surprise, la classe Eleve représente une personne, et plus spécifiquement un élève. La classe NoteEleve est un "wrapper" qui possède un objet Eleve et une note (sur 20) associée. Quant à l'enum Sexe, son rôle dans l'histoire est évident.
2-C. Les données à lire
Dans ce tutoriel, nous allons utiliser deux fichiers CSV. Le premier, nommé "eleves.csv", contient la liste des élèves. Le second, nommé "notes-dernier-exam.csv", contient quant à lui les notes desdits élèves au dernier examen.
 | Dans un fichier CSV, les données sont séparées par des virgules, ou un point-virgule pour le format CSV français standard. |
| eleves.csv |
# Nom;Prénom;Classe;Sexe;Date de naissance;Adresse
Durand;Marie;3;F;02/01/1992;15 rue du Lac 75001 Paris
Alesi;Julie;3;F;08/01/1992;72 av. Jean Dupont 75003 Paris
Martini;Carine;3;F;17/01/1992;2 rue du Moulin 92230 Neullavy
Varola;Sophie;3;F;21/01/1992;15 rue du Lac 75001 Paris
Labiche;Lelou;3;F;21/01/1992;15 rue du Lac 75001 Paris
Dujardin;Anne;3;F;03/02/1992;67 rue des Jardins 91800 Brunoy
Laventure;Martine;3;F;15/02/1992;15 rue du Lac 75001 Paris
...
Fivolini;Kevin;3;H;06/12/1992;15 rue du Lac 75001 Paris
Laferme;Martin;3;H;07/12/1992;15 rue du Lac 75001 Paris
Dupuis;Vincent;3;H;15/12/1992;15 rue du Lac 75001 Paris
Lagrange;Alexandre;3;H;28/12/1992;15 rue du Lac 75001 Paris
|
 | On constate que de nombreux élèves habitent au "15 rue du Lac". Cette adresse est celle de la résidence universitaire de l'école. |
| notes-dernier-exam.csv |
# Nom;Prénom;Note
Durand;Marie;5
Alesi;Julie;8
Martini;Carine;10,5
Varola;Sophie;12
Labiche;Lelou;12
Dujardin;Anne;13
Laventure;Martine;14
...
Fivolini;Kevin;19
Laferme;Martin;20
Dupuis;Vincent;20
|
 | On remarque que "Alexandre Lagrange", que j'ai mis en fin de fichier pour simplifier la lecture, n'a pas de note au dernier examen ; il était absent. Dans ce tutoriel, nous dirons qu'une absence vaut un zéro. Il faudra donc gérer ce cas. |
3. Action
3-A. Compléter le modèle
Durée estimée : 30 secondes.
Pour commencer, on doit ajouter les attributs "date de naissance" et "adresse", qui ne sont pas encore dans "Eleve.java" et modifier le constructeur de la classe en conséquence.
| Nouveaux attributs dans Eleve.java |
public class Eleve {
private String nom;
private String prenom;
private Integer annee;
private Sexe sexe;
private Date dateNaissance;
private String adresse;
public Eleve(String nom, String prenom, Integer annee, Sexe sexe, Date dateNaissance, String adresse) {
...
}
...
}
|
3-B. Créer des DAO vides
Durée estimée : 1 minute.
Nous allons créer deux DAO vides : un pour charger la liste des élèves et l'autre pour charger les notes. Chaque DAO ne renvoie qu'une partie des informations disponibles. Nous verrons dans un prochain tutoriel comment réconcilier les données, ce qui n'est pas le sujet ici.
| NoteDao.java |
package com.thi.notes.dao;
import java.util.Map;
public class NoteDao {
public Map<String, Double> findNotesDernierExam() {
return null;
}
}
|
Ce DAO (Data Access Object) renvoie une "Map" dont les clés sont les noms (prénom + nom) des élèves et les valeurs sont les notes obtenues au dernier examen.
| EleveDao.java |
package com.thi.notes.dao;
import java.util.List;
import com.thi.notes.domain.Eleve;
public class EleveDao {
public List<Eleve> findEleves() {
return null;
}
}
|
Ce DAO renvoie la liste des élèves, tout simplement, en utilisant les objets Eleve et Sexe. Pour lire les données à l'aide de EleveDao, on utilisera un code ressemblant au suivant.
| Utilisation de EleveDao |
final EleveDao eleveDao = new EleveDao();
final List<Eleve> eleves = eleveDao.findEleves();
for(Eleve eleve : eleves) {
System.out.println(eleve);
}
|
Dans la suite de ce tutoriel, nous allons nous concentrer sur "EleveDao.java", l'autre DAO utilisant globalement les mêmes principes. Un code d'exemple est toutefois proposé en annexe et dans le fichier Zip final.
3-C. Ajout d'Open-CSV
Durée estimée : 30 secondes.
Pour utiliser Open CSV dans un projet Java-Maven, il suffit d'ajouter une dépendance dans le "pom.xml".
| Dépendance vers Open CSV |
<dependency>
<groupId>net.sf.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>2.3</version>
</dependency>
|
Puis, comme d'habitude, il faut relancer une installation Maven.
| Maven |
mvn clean install eclipse:eclipse
|
En fonction des éléments déjà présents sur l'ordinateur, la réponse de Maven devrait ressembler à la trace suivante.
| Maven |
C:\dvp\notes>mvn clean install eclipse:eclipse
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Notes 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ notes ---
[INFO] Deleting C:\dvp\notes\target
[INFO]
[INFO] --- maven-resources-plugin:2.4.3:resources (default-resources) @ notes ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO]
[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ notes ---
[INFO] Compiling 9 source files to C:\dvp\notes\target\classes
[INFO]
[INFO] --- maven-resources-plugin:2.4.3:testResources (default-testResources) @ notes ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 0 resource
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 10.197s
[INFO] Finished at: Wed Jan 18 20:19:12 CET 2012
[INFO] Final Memory: 12M/59M
|
3-D. Lecture des données
Durée estimée : 3 minutes.
On entre dans le vif du sujet. Comme indiqué plus haut, nous allons nous concentrer sur la lecture de la liste d'élèves.
Pour commencer, il faut accéder au fichier CSV.
| Utilisation du helper |
public class EleveDao {
private final static String RESOURCES_PATH = "src/main/resources/";
private final static String ELEVES_FILE_NAME = "eleves.csv";
public List<Eleve> findEleves() {
File file = new File(RESOURCES_PATH + ELEVES_FILE_NAME);
FileReader fr = new FileReader(file);
...
}
}
|
Puis j'utilise l'objet "CSVReader" fourni par la bibliothèque "Open-CSV".
| Utilisation du helper, sans la gestion des exceptions |
public class EleveDao {
private final static char SEPARATOR = ';';
...
public List<Eleve> findEleves() {
File file = new File(RESOURCES_PATH + ELEVES_FILE_NAME);
FileReader fr = new FileReader(file);
CSVReader csvReader = new CSVReader(fr, SEPARATOR);
...
|
Ce "reader" nous permet de lire les données du fichier.
| Lire les données |
List<String[] > data = new ArrayList<String[] >();
String[] nextLine = null;
while ((nextLine = csvReader.readNext()) != null) {
int size = nextLine.length;
if (size == 0) {
continue;
}
String debut = nextLine[0].trim();
if (debut.length() == 0 && size == 1) {
continue;
}
if (debut.startsWith("#")) {
continue;
}
data.add(nextLine);
}
|
Il ne reste plus qu'à transformer les données, qu'on a sous forme de tableau de String, en objets Eleve.
| Transformer les données en objets |
List<String[] > data = new ArrayList<String[] >();
...
List<Eleve> eleves = new ArrayList<Eleve>();
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
for (String[] oneData : data) {
String nom = oneData[0];
String prenom = oneData[1];
String classeStr = oneData[2];
String sexeStr = oneData[3];
String dateNaissanceStr = oneData[4];
String adresse = oneData[5];
Integer classe = Integer.parseInt(classeStr);
Sexe sexe = (sexeStr.equalsIgnoreCase("F")) ? FEMME : HOMME;
Date dateNaissance = dateFormat.parse(dateNaissanceStr);
Eleve eleve = new Eleve(nom, prenom, classe, sexe, dateNaissance, adresse);
eleves.add(eleve);
}
return eleves;
|
Ici, la seule petite difficulté vient de la transformation de la date de naissance, d'un String vers un objet Date, ce que l'on fait à l'aide des classes Java "DateFormat" et "SimpleDateFormat".
| Transformer de la date de naissance |
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
String dateNaissanceStr = "28/01/1992";
Date dateNaissance = dateFormat.parse(dateNaissanceStr);
|
 | Le tutoriel "fichiers CSV en Java" propose une façon plus élégante de transformer les lignes du fichier en liste d'objets. |
Il ne reste plus qu'à réorganiser un peu le code (pour éviter d'avoir des méthodes trop grosses) et à factoriser les traitements (et ainsi ne pas dupliquer de code dans l'autre DAO). Le code final, avec ces changements, est disponible en annexe.
4. Conclusions
Comme on vient de le constater, il est relativement simple de lire un fichier CSV à l'aide d'une bibliothèque telle que Open-CSV. Cette dernière réalise un ensemble de traitements complexes et en masque la complexité. Il existe d'autres bibliothèques sur le marché, qui fonctionnent différemment et que je vous invite à regarder, au moins pas curiosité.
5. Remerciements
Je tiens à remercier, en tant qu'auteur de tutoriel rapide, toutes les personnes qui m'ont aidé et soutenu. Je pense tout d'abord à mes collègues qui subissent mes questions au quotidien mais aussi à mes contacts et amis du Web, dans le domaine de l'informatique ou non, qui m'ont fait part de leurs remarques et critiques. Bien entendu, je n'oublie pas l'équipe de developpez.com qui m'a guidé dans la rédaction de cet article et m'a aidé à le corriger et le faire évoluer, principalement sur le forum.
Plus particulièrement j'adresse mes remerciements, à
Claude LELOUP (
ClaudeLELOUP),
Mickael BARON (keulkeul),
Nemek
et Yan BONNEL.
6. Annexes
6-A. Liens
6-B. Les fichiers importants en entier
| Le helper CsvFileHelper.java |
package com.thi.notes.dao;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import au.com.bytecode.opencsv.CSVReader;
public class CsvFileHelper {
public static List<String[] > readCsvFile(String fileName, char separator) {
final List<String[] > data = new ArrayList<String[] >();
try {
final File file = new File(fileName);
final FileReader fr = new FileReader(file);
final CSVReader csvReader = new CSVReader(fr, separator);
String[] nextLine = null;
while ((nextLine = csvReader.readNext()) != null) {
final int size = nextLine.length;
if (size == 0) {
continue;
}
final String debut = nextLine[0].trim();
if (debut.length() == 0 && size == 1) {
continue;
}
if (debut.startsWith("#")) {
continue;
}
data.add(nextLine);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
}
|
| Interface EleveDao.java |
package com.thi.notes.dao;
import java.util.List;
import com.thi.notes.domain.Eleve;
public interface EleveDao {
List<Eleve> findEleves();
}
|
| Implémentation CsvEleveDao.java |
package com.thi.notes.dao;
import static com.thi.notes.dao.CsvFileHelper.readCsvFile;
import static com.thi.notes.domain.Sexe.FEMME;
import static com.thi.notes.domain.Sexe.HOMME;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import com.thi.notes.domain.Eleve;
import com.thi.notes.domain.Sexe;
public class CsvEleveDao implements EleveDao {
private final static char SEPARATOR = ';';
private final static String RESOURCES_PATH = "src/main/resources/";
private final static String ELEVES_FILE_NAME = "eleves.csv";
@Override
public List<Eleve> findEleves() {
final List<String[] > data = readCsvFile(RESOURCES_PATH + ELEVES_FILE_NAME, SEPARATOR);
final List<Eleve> eleves = dataToEleves(data);
return eleves;
}
private List<Eleve> dataToEleves(List<String[] > data) {
final List<Eleve> eleves = new ArrayList<Eleve>();
try {
final DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
for (String[] oneData : data) {
final String nom = oneData[0];
final String prenom = oneData[1];
final String classeStr = oneData[2];
final String sexeStr = oneData[3];
final String dateNaissanceStr = oneData[4];
final String adresse = oneData[5];
final Integer classe = Integer.parseInt(classeStr);
final Sexe sexe = (sexeStr.equalsIgnoreCase("F")) ? FEMME : HOMME;
final Date dateNaissance = dateFormat.parse(dateNaissanceStr);
final Eleve eleve = new Eleve(nom, prenom, classe, sexe, dateNaissance, adresse);
eleves.add(eleve);
}
} catch (ParseException e) {
e.printStackTrace();
}
return eleves;
}
}
|
Dans un prochain tutoriel, je vous montrerai comment charger la liste d'élèves à partir d'une base de données MySql, et non plus à partir d'un fichier CSV. Néanmoins, la signature de la méthode findEleves ne devrait pas changer. C'est pourquoi j'ai ajouté une interface. Comme vous pouvez le deviner, de la même manière que CsvEleveDao implémente EleveDao, le prochain tutoriel introduira l'implémentation DatabaseEleveDao de EleveDao pour lire les données depuis la base.
| Interface NoteDao.java |
package com.thi.notes.dao;
import java.util.Map;
public interface NoteDao {
Map<String, Double> findNotesDernierExam();
}
|
| Implémentation CsvNoteDao.java |
package com.thi.notes.dao;
import static com.thi.notes.dao.CsvFileHelper.readCsvFile;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CsvNoteDao implements NoteDao {
private final static char SEPARATOR = ';';
private final static String RESOURCES_PATH = "src/main/resources/";
private final static String ELEVES_FILE_NAME = "notes-dernier-exam.csv";
@Override
public Map<String, Double> findNotesDernierExam() {
final List<String[] > data = readCsvFile(RESOURCES_PATH + ELEVES_FILE_NAME, SEPARATOR);
final Map<String, Double> map = dataToMap(data);
return map;
}
private Map<String, Double> dataToMap(List<String[] > data) {
final Map<String, Double> map = new HashMap<String, Double>();
for (String[] oneData : data) {
final String nom = oneData[0];
final String prenom = oneData[1];
final String noteStr = oneData[2];
final Double note = new Double(noteStr.replace(",", "."));
map.put(nom + " " + prenom, note);
}
return map;
}
}
|
| DaoLauncher.java pour vérifier que ça marche |
package com.thi.notes;
import java.util.List;
import java.util.Map;
import com.thi.notes.dao.CsvEleveDao;
import com.thi.notes.dao.CsvNoteDao;
import com.thi.notes.dao.EleveDao;
import com.thi.notes.dao.NoteDao;
import com.thi.notes.domain.Eleve;
public class DaoLauncher {
public static void main(String[] args) {
final EleveDao eleveDao = new CsvEleveDao();
final List<Eleve> eleves = eleveDao.findEleves();
System.out.println("Liste des eleves");
for (Eleve eleve : eleves) {
System.out.println(eleve);
}
final NoteDao noteDao = new CsvNoteDao();
final Map<String, Double> notes = noteDao.findNotesDernierExam();
System.out.println("Notes des eleves");
for (String key : notes.keySet()) {
final Double note = notes.get(key);
System.out.println(key + " : " + note);
}
}
}
|
6-C. Utilisation de la lib MoteurCsv
Comme me l'a proposé
Yan Bonnel,
j'ai adapté le code présenté ci-dessus pour employer
la
bibliothèque MoteurCsv, qui ressemble un peu à JPA dans sont utilisation.
Tout d'abord, je change mon pom.xml, sachant que MoteurCsv possède déjà une dépendance vers OpenCSV.
| Extrait du fichier pom.xml utilisant MoteurCsv |
<dependency>
<groupId>fr.ybo</groupId>
<artifactId>moteurcsv</artifactId>
<version>1.1.3</version>
</dependency>
|
| pom.xml utilisant MoteurCsv |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.thi</groupId>
<artifactId>notes-avec-moteurcsv</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
...
<developers>
<developer><name>Thierry Leriche-Dessirier</name></developer>
<developer><name>Yan Bonnel</name></developer>
</developers>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>4.8.2</junit.version>
<jfreechart.version>1.0.14</jfreechart.version>
<moteurcsv.version>1.1.3</moteurcsv.version>
</properties>
<dependencyManagement>
<dependencies>
...
<dependency>
<groupId>fr.ybo</groupId>
<artifactId>moteurcsv</artifactId>
<version>${moteurcsv.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
...
<dependency>
<groupId>fr.ybo</groupId>
<artifactId>moteurcsv</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<encoding>UTF-8</encoding>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>ybonnel-release</id>
<url>https://repository-ybonnel.forge.cloudbees.com/release/</url>
</repository>
</repositories>
</project>
|
Je vais ensuite modifier mes beans pour que ça ressemble à du JPA.
| Eleve.java |
@FichierCsv(separateur = ";")
public class Eleve {
@BaliseCsv("Nom")
private String nom;
@BaliseCsv("Prénom")
private String prenom;
@BaliseCsv(value = "Classe", adapter = AdapterInteger.class)
private Integer annee;
@BaliseCsv(value = "Sexe", adapter = AdapterSexe.class)
private Sexe sexe;
@BaliseCsv(value = "Date de naissance", adapter = AdapterDate.class)
private Date dateNaissance;
@BaliseCsv(value = "Adresse")
private String adresse;
public Eleve() {
}
...
|
| Sexe.java |
public enum Sexe {
HOMME("Garçon"),
FEMME("Fille");
private final String label;
Sexe(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
public static class AdapterSexe implements AdapterCsv<Sexe> {
@Override
public Sexe parse(String chaine) {
return (chaine.equalsIgnoreCase("F")) ? FEMME : HOMME;
}
@Override
public String toString(Sexe objet) {
return objet == FEMME ? "F" : "H";
}
}
}
|
Je peux maintenant passer à la lecture du fichier.
| CsvEleveDao.java |
public class CsvEleveDao implements EleveDao {
private final static char SEPARATOR = ';';
private final static String RESOURCES_PATH = "src/main/resources/";
private final static String ELEVES_FILE_NAME = "eleves.csv";
private final static MoteurCsv moteurCsv = new MoteurCsv(Eleve.class);
@Override
public List<Eleve> findEleves() {
List<Eleve> eleves = null;
try {
eleves = moteurCsv.parseInputStream(new FileInputStream(new File(RESOURCES_PATH + ELEVES_FILE_NAME)), Eleve.class);
} catch (FileNotFoundException e) {
e.printStackTrace();
eleves = new ArrayList<Eleve>();
}
return eleves;
}
public static class AdapterDate implements AdapterCsv<Date> {
final DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
@Override
public Date parse(String chaine) {
try {
return dateFormat.parse(chaine);
} catch (ParseException e) {
return null;
}
}
@Override
public String toString(Date objet) {
return dateFormat.format(objet);
}
}
|
 |
Ici, je ne m'occupe que de la liste des élèves. Pour lire l'autre fichier, il faut faire
la même chose.
|
Petit détail qui compte, MoteurCsv a besoin, par défaut, que la première ligne importante
contienne les noms des champs, puisqu'ils sont utilisés pour "mapper" les objets.
| eleves.csv |
Nom;Prénom;Classe;Sexe;Date de naissance;Adresse
Durand;Marie;3;F;02/01/1992;15 rue du Lac 75001 Paris
Alesi;Julie;3;F;08/01/1992;72 av. Jean Dupont 75003 Paris
Martini;Carine;3;F;17/01/1992;2 rue du Moulin 92230 Neullavy
...
|
Et voilà... C'est encore plus simple.
Le code final de ce tutoriel, incluant l'utilisation de MoteurCsv est disponible dans le fichier
ZIP
notes4_moteurcsv.zip.


Les sources présentées sur cette page sont libres de droits
et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation
constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ©
2011 Thierry Leriche-Dessirier. Aucune reproduction,
même partielle, ne peut être faite de ce site et de l'ensemble de son contenu :
textes, documents, images, etc. sans l'autorisation expresse de l'auteur.
Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 €
de dommages et intérêts.
Cette page est déposée.