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-CSVOpen-CSV (et MoteurCsv en annexe), 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.
Ce tutoriel s'inspire très largement de mon article sur la lecture des fichiers CSV en JavaLes fichier CSV en Java. Ce tutoriel reprend également les objets utilisés dans les articles « Afficher un tableau avec un Table Model Swing en 5 minutes » et « Afficher un graphe jfreechart en 5 minutes ». Même si elle est conseillée, la lecture de ces articles n'est pas indispensable pour la suite.
1-C. Mise à jour▲
27 février 2012 : Ajout d'un exemple d'utilisation de la lib MoteurCsv (en annexe).
12 juillet 2012 : Prise en compte de la nouvelle version 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 commencer, je vous propose de télécharger le fichier Zip « notes3_domain.zip », contenant un projet Java-Maven d'exemple.
Compilez le projet d'exemple et importez-le dans Eclipse (comme expliqué dans le tutoriel « Importer un projet Maven dans Eclipse en 5 minutes ») ou dans l'IDE de votre choix.
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.
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;
}
}
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) {
...
}
// + getter-setter
}
package
com.thi.notes.domain;
public
class
NoteEleve {
private
Eleve eleve;
private
Double note;
public
NoteEleve
(
Eleve eleve, Double note) {
...
}
// + getter-setter
}
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.
# 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.
# 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.
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) {
...
}
// + getter-setter
...
}
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.
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.
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.
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 ».
<dependency>
<groupId>
net.sf.opencsv</groupId>
<artifactId>
opencsv</artifactId>
<version>
2.3</version>
</dependency>
Puis, comme d'habitude, il faut relancer une installation 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.
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.
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 ».
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.
List<
String[] >
data =
new
ArrayList<
String[] >(
);
String[] nextLine =
null
;
while
((
nextLine =
csvReader.readNext
(
)) !=
null
) {
int
size =
nextLine.length;
// ligne vide
if
(
size ==
0
) {
continue
;
}
String debut =
nextLine[0
].trim
(
);
if
(
debut.length
(
) ==
0
&&
size ==
1
) {
continue
;
}
// ligne de commentaire
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.
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 ».
DateFormat dateFormat =
new
SimpleDateFormat
(
"dd/MM/yyyy"
);
String dateNaissanceStr =
"28/01/1992"
; // Par exemple
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é.
Et bien entendu, je vous encourage à lire mon tutoriel sur les fichiers CSV en JavaLes fichier CSV en Java.
Le code final de ce tutoriel est disponible dans le fichier ZIP notes4_domain-et-dao-csv.zip.code final
Retrouvez les tutoriels de la série « en 5 minutes » sur developpez.com à l'adresse https://thierry-leriche-dessirier.developpez.com/#page_articlesEn 5 minutes.
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▲
Le site Web d'Open-CSV est disponible à l'adresse
http://opencsv.sourceforge.net
Pour suivre cet article, je conseille la lecture des tutoriels
« Importer un projet Maven dans Eclipse en 5 minutes » disponible à l'adresse
https://thierry-leriche-dessirier.developpez.com/tutoriels/java/importer-projet-maven-dans-eclipse-5-minImporter un projet Maven dans Eclipse en 5 minutes
Je vous encourage à lire mon tutoriel sur les fichiers CSV en Java, disponible à l'adresse
https://thierry-leriche-dessirier.developpez.com/tutoriels/java/csv-avec-javaLes fichier CSV en Java
6-B. Les fichiers importants en entier▲
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;
// ligne vide
if
(
size ==
0
) {
continue
;
}
final
String debut =
nextLine[0
].trim
(
);
if
(
debut.length
(
) ==
0
&&
size ==
1
) {
continue
;
}
// ligne de commentaire
if
(
debut.startsWith
(
"#"
)) {
continue
;
}
data.add
(
nextLine);
}
}
catch
(
FileNotFoundException e) {
e.printStackTrace
(
);
}
catch
(
IOException e) {
e.printStackTrace
(
);
}
return
data;
}
}
package
com.thi.notes.dao;
import
java.util.List;
import
com.thi.notes.domain.Eleve;
public
interface
EleveDao {
List<
Eleve>
findEleves
(
);
}
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.
package
com.thi.notes.dao;
import
java.util.Map;
public
interface
NoteDao {
Map<
String, Double>
findNotesDernierExam
(
);
}
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;
}
}
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 BonnelBlog de Yan Bonnel, j'ai adapté le code présenté ci-dessus pour employer la bibliothèque MoteurCsvPage du projet MoteurCsv, qui ressemble un peu à JPA dans son utilisation.
Tout d'abord, je change mon pom.xml, sachant que MoteurCsv possède déjà une dépendance vers OpenCSV.
<!-- MoteurCSV -->
<dependency>
<groupId>
fr.ybo</groupId>
<artifactId>
moteurcsv</artifactId>
<version>
1.1.3</version>
</dependency>
<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>
<!-- Thierry -->
<developer><name>
Thierry Leriche-Dessirier</name></developer>
<!-- Yan -->
<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>
<!-- Remplacement de opencsv par moteurcsv -->
<!--<opencsv.version>2.3</opencsv.version>-->
<moteurcsv.version>
1.1.3</moteurcsv.version>
</properties>
<dependencyManagement>
<dependencies>
...
<!-- Open CSV -->
<!--<dependency>
<groupId>net.sf.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>${opencsv.version}</version>
</dependency>-->
<!-- MoteurCSV -->
<dependency>
<groupId>
fr.ybo</groupId>
<artifactId>
moteurcsv</artifactId>
<version>
${moteurcsv.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
...
<!-- Open CSV -->
<!--<dependency>
<groupId>net.sf.opencsv</groupId>
<artifactId>opencsv</artifactId>
</dependency>-->
<!-- MoteurCSV -->
<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.
@FichierCsv
(
separateur =
";"
)
public
class
Eleve {
// private String nom;
// private String prenom;
// private Integer annee;
// private Sexe sexe;
// private Date dateNaissance;
// private String adresse;
@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
(
) {
// Constructeur par defaut obligatoire pour MoteurCsv.
}
...
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.
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"
;
// Moteur CSV
private
final
static
MoteurCsv moteurCsv =
new
MoteurCsv
(
Eleve.class
);
@Override
public
List<
Eleve>
findEleves
(
) {
// final List<String[] > data = readCsvFile(RESOURCES_PATH +
// ELEVES_FILE_NAME, SEPARATOR);
// final List<Eleve> eleves = dataToEleves(data);
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.
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.code final
6-C-1. Version 1.2.0 de la lib▲
Mise à jour : 12 juillet 2012.
Les nouvelles versions de la lib MoteurCsv (par exemple la version 1.2.0) s'utilisent d'une autre manière que ce qui est présenté ci-dessus. La méthode « parseInputStream() » renvoie désormais un objet de type « Resultat » et non plus la liste des objets lus.
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"
;
// Moteur CSV
private
final
static
MoteurCsv moteurCsv =
new
MoteurCsv
(
Eleve.class
);
@Override
public
List<
Eleve>
findEleves
(
) {
Resultat<
Eleve>
resultat =
moteurCsv.parseInputStream
(
new
FileInputStream
(
new
File
(
RESOURCES_PATH +
ELEVES_FILE_NAME)), Eleve.class
);
List<
Eleve>
eleves =
resultat.getObjets
(
);
Cet objet « Resultat » propose la méthode « getErreurs() » qui montre les éventuelles erreurs qui sont arrivées durant les traitements.
En plus de ce changement, la lib propose une nouvelle syntaxe (prog fonc) qui fera un peu penser à celle utilisée dans Guava. Elle permet de traiter les éléments trouvés directement.
public
class
CsvEleveDao implements
EleveDao {
final
MoteurCsv moteurCsv =
new
MoteurCsv
(
Eleve.class
);
...
@Override
public
List<
Eleve>
findEleves
(
) {
final
File f =
new
File
(
RESOURCES_PATH +
ELEVES_FILE_NAME);
final
FileReader fr =
new
FileReader
(
f);
final
List<
Eleve>
eleves =
newArrayList
(
); // Static factory Guava
moteurCsv.parseFileAndInsert
(
fr, Eleve.class
, new
InsertObject<
Eleve>(
) {
@Override
public
void
insertObject
(
Eleve eleve) {
foo
(
eleve); // Faire un truc sur l'eleve.
...
result.add
(
eleve); // Mettre dans la liste, si besoin.
...
System.out.println
(
eleve); // Un petit sysout pour le plaisir.
}
}
);