On nous demande de réaliser une copie de fichier, à l'aide de deux paramètres passés dans la console, lors du lancement du programme. Une grande partie du code de ce chapitre, peut être réutilisée : on s'inspirera des codes d'utilisation des flux d'octets et des codes d'utilisation des tampons.
Cet exercice ne présente pas de difficulté majeure. Mais tout de même quelques remarques par rapport au code que je vais vous soumettre :
- j'ai pris soin de vérifier que l'on a bien deux arguments dans la ligne de commandes ;
- voici un exemple d'erreur de type FileNotFoundException :
at java.io.FileInputStream.open
(
Native Method)
at java.io.FileInputStream.<
init>(
FileInputStream.java:137
)
at java.io.FileInputStream.<
init>(
FileInputStream.java:96
)
at CopieFichier.copier
(
CopieFichier.java:182
)
at CopieFichier.main
(
CopieFichier.java:171
)
Le message de l'exception est alors ce qui se situe en première ligne, juste après les deux points.
Comme le premier contenu du message est le nom du fichier que l'on a tenté d'ouvrir, on va tenter de l'extraire. En appelant la méthode split(" ") - la chaine en paramètre se constitue d'un seul espace - sur une chaine de caractères, on coupe la chaine selon ses espaces.
String s =
"Ceci est, un exemple, un simple exemple."
;
String [] morceaux =
s.split
(
" "
);
On obtient donc le tableau morceaux suivant :
{
" Ceci "
, " est, "
, " un "
, " exemple, "
, " un "
, " simple "
, " exemple. "
}
Ainsi pour extraire le nom du fichier, on appellera :
exception.getMessage
(
).split[0
];
- j'ai préféré construire une méthode qui gère la copie, plutôt que de coder le tout en dur dans le main() ;
- enfin on referme, dans la clause finally, les différents flux. On prend soin de fermer les flux de lecture avant les flux d'écriture (et un tampon avant le flux auquel il est relié).
Voici donc le code que j'ai à vous proposer :
Copie de fichier (mode console)
import
java.io.BufferedInputStream;
import
java.io.BufferedOutputStream;
import
java.io.FileInputStream;
import
java.io.FileNotFoundException;
import
java.io.FileOutputStream;
import
java.io.IOException;
import
javax.swing.JOptionPane;
public
class
CopieFichierModeConsole {
public
static
void
main
(
String[] args) {
if
(
args.length !=
2
){
System.err.println
(
"Utilisation : CopierFicher source destination"
);
System.exit
(
1
);
}
CopieFichierModeConsole copieurFichier =
new
CopieFichierModeConsole
(
);
copieurFichier.copier
(
args[0
], args[1
]);
}
public
void
copier
(
String source, String destination){
FileInputStream fichierLecture =
null
;
FileOutputStream fichierSauvegarde =
null
;
BufferedInputStream tamponFichierLecture =
null
;
BufferedOutputStream tamponFichierSauvegarde =
null
;
try
{
fichierLecture =
new
FileInputStream
(
source);
tamponFichierLecture =
new
BufferedInputStream
(
fichierLecture);
fichierSauvegarde =
new
FileOutputStream
(
destination);
tamponFichierSauvegarde =
new
BufferedOutputStream
(
fichierSauvegarde);
while
(
true
){
int
valeurEntiereOctet =
tamponFichierLecture.read
(
);
if
(
valeurEntiereOctet ==
-
1
)
break
;
tamponFichierSauvegarde.write
(
valeurEntiereOctet);
}
}
catch
(
FileNotFoundException e) {
e.printStackTrace
(
);
String [] motsDuMessage =
e.getMessage
(
).split
(
" "
);
String message =
"Impossible d'ouvrir le fichier "
+
motsDuMessage[0
]+
" ."
+
"
\n
Verifiez que le fichier existe et qu'il ne s'agisse pas"
+
" du tout d'un repertoire."
;
JOptionPane.showMessageDialog
(
null
,message,
"Erreur d'ouverture de fichier"
, JOptionPane.ERROR_MESSAGE);
}
catch
(
IOException e) {
e.printStackTrace
(
);
JOptionPane.showMessageDialog
(
null
,
"Un erreur de lecture ou d'ecriture diverse est survenue."
,
"Erreur diverse"
, JOptionPane.ERROR_MESSAGE);
}
finally
{
try
{
tamponFichierSauvegarde.flush
(
);
tamponFichierLecture.close
(
);
fichierLecture.close
(
);
tamponFichierSauvegarde.close
(
);
fichierSauvegarde.close
(
);
}
catch
(
IOException exception){
exception.printStackTrace
(
);
}
}
}
}
VIII-B-1. Utilisation du composant Swing JFileChooser▲
Ce composant permet d'afficher une boîte de dialogue Ouvrir/EnregisterSous, nous permettant donc de choisir un fichier grâce à une fenêtre conviviale.
Tout d'abord, il faut créer une instance de JFileChooser. On peut ensuite se contenter d'appeler :
- sa méthode showOpenDialog pour afficher une fenêtre de sélection de fichier pour une ouverture ;
- sa méthode showSaveDialog pour afficher une fenêtre de sélection de fichier pour une sauvegarde.
Dans les deux cas, on obtient un int en retour, nous indiquant de quelle manière l'utilisateur a quitté la fenêtre. S'il a validé sa sélection, on obtient la valeur JFileChooser.APPROVE_OPTION.
Ceci fait, on dispose de plusieurs méthodes nous renseignant sur la dernière sélection utilisateur, dont les plus utiles ici seront :
- getSelectedFile() : on obtient un objet de type File, correspondant au fichier sélectionné ;
- getCurrentDirectory() : on obtient le répertoire du fichier sélectionné.
Enfin, le constructeur
JFileChooser
(
File currentDirectory)
permet de choisir le répertoire affiché lors du lancement du menu : une valeur de null laissera le menu afficher le répertoire par défaut.
VIII-B-2. L'utilisation de classe locale et des constantes▲
Vous connaissiez les variables locales : eh bien sachez maintenant que vous pouvez aussi déclarer des classes localement à une méthode. Bien sûr les inconvénients principaux d'une telle pratique :
- la classe ne sera pas réutilisable en dehors de la méthode où elle a été déclarée ;
- cela ne va pas en améliorant la clarté, la lisibilité du code.
Alors pourquoi utiliser de telles classes ? J'ai choisi de déclarer localement deux classes implémentant l'interface ActionListener dans le constructeur, parce que de cette manière les variables locales au constructeur peuvent être directement réutilisées dans la classe interne. Seule condition : que l'on déclare les variables réutilisées comme des constantes, grâce au mot-clé final.
final
int
monEntierConstant =
10
;
Une constante est une variable qui ne pourra jamais être modifiée, sous peine d'obtenir une erreur de compilation. Les constantes peuvent aussi être utiles pour éviter de coder les variables en dur. Ainsi au lieu d'écrire, pour redimensionner une fenêtre :
Vous pouvez écrire :
final
int
tailleEnX =
10
;
final
int
tailleEnY =
20
;
fenetre.setSize
(
tailleEnX, tailleEnY) ;
Voici un exemple de déclaration/utilisation d'une classe interne dans une méthode :
Exemple de classe interne locale à une méthode
Sélectionnez
void
construireFenetre
(
){
final
String texte1 =
"MonTexte1"
;
final
String texte2 =
"AutreTexte2"
;
final
JButton monBouton =
new
JButton
(
texte1) ;
class
MonActionPourBouton implements
ActionListener {
public
void
actionPerformed
(
ActionEvent evt){
if
(
texte1.equals
(
monBouton.getText
(
)){
monBouton.setText
(
texte2) ;
}
else
if
(
texte2.equals
(
monBouton.getText
(
)){
monBouton.setText
(
texte1) ;
}
}
}
;
}
monBouton.addActionListener
(
new
MonActionPourBouton
(
)) ;
Ici le texte du bouton basculera entre le contenu de texte1 et le contenu de texte2 à chaque clic.
VIII-B-3. Dernières considérations▲
J'ai réutilisé la méthode copier() de l'exercice précédent presque telle quelle : dans chaque close catch, je n'affiche plus mon message d'erreur personnalisé, mais je me contente de renvoyer une exception du même type en remplaçant le message par le mien.
La classe CopieFichier est maintenant une classe fille de la classe JFrame.
VIII-B-4. Le code complet▲
Copie de fichier (version graphique)
import
java.awt.GridLayout;
import
java.awt.event.ActionEvent;
import
java.awt.event.ActionListener;
import
java.io.BufferedInputStream;
import
java.io.BufferedOutputStream;
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.FileNotFoundException;
import
java.io.FileOutputStream;
import
java.io.IOException;
import
javax.swing.JButton;
import
javax.swing.JFileChooser;
import
javax.swing.JFrame;
import
javax.swing.JLabel;
import
javax.swing.JOptionPane;
import
javax.swing.JTextField;
public
class
CopieFichierModeGraphique extends
JFrame {
File fichierSource =
null
, fichierDestination =
null
;
File repertoireSource =
null
, repertoireDestination =
null
;
public
CopieFichierModeGraphique
(
){
setTitle
(
"Copie de fichiers"
);
setDefaultCloseOperation
(
JFrame.EXIT_ON_CLOSE);
setLayout
(
new
GridLayout
(
4
, 3
));
add
(
new
JLabel
(
"Copier depuis : "
));
final
JTextField texteSource =
new
JTextField
(
30
);
texteSource.setEditable
(
false
);
add
(
texteSource);
JButton boutonSource =
new
JButton
(
"Parcourir ..."
);
class
ActionBoutonSource implements
ActionListener {
@Override
public
void
actionPerformed
(
ActionEvent evt) {
JFileChooser fenetreChoixFichier =
new
JFileChooser
(
repertoireSource);
int
modeFermeture =
fenetreChoixFichier.showOpenDialog
(
CopieFichierModeGraphique.this
);
if
(
modeFermeture ==
JFileChooser.APPROVE_OPTION){
repertoireSource =
fenetreChoixFichier.getCurrentDirectory
(
);
fichierSource =
fenetreChoixFichier.getSelectedFile
(
);
texteSource.setText
(
fichierSource.getAbsolutePath
(
));
}
}
}
;
boutonSource.addActionListener
(
new
ActionBoutonSource
(
));
add
(
boutonSource);
add
(
new
JLabel
(
"Copier vers : "
));
final
JTextField texteDestination =
new
JTextField
(
30
);
texteDestination.setEditable
(
false
);
add
(
texteDestination);
JButton boutonDestination =
new
JButton
(
"Parcourir ..."
);
class
ActionBoutonDestination implements
ActionListener {
@Override
public
void
actionPerformed
(
ActionEvent evt) {
JFileChooser fenetreChoixFichier =
new
JFileChooser
(
repertoireDestination);
int
modeFermeture =
fenetreChoixFichier.showSaveDialog
(
CopieFichierModeGraphique.this
);
if
(
modeFermeture ==
JFileChooser.APPROVE_OPTION){
repertoireDestination =
fenetreChoixFichier.getCurrentDirectory
(
);
fichierDestination =
fenetreChoixFichier.getSelectedFile
(
);
texteDestination.setText
(
fichierDestination.getAbsolutePath
(
));
}
}
}
;
boutonDestination.addActionListener
(
new
ActionBoutonDestination
(
));
add
(
boutonDestination);
add
(
new
JLabel
(
));
JButton boutonCopier =
new
JButton
(
"Copier"
);
class
ActionBoutonCopier implements
ActionListener {
@Override
public
void
actionPerformed
(
ActionEvent evt) {
if
(
fichierSource ==
null
){
JOptionPane.showMessageDialog
(
CopieFichierModeGraphique.this
,
"Veuillez selectionner un fichier source."
,
"Selection incomplete"
,
JOptionPane.ERROR_MESSAGE
);
return
;
}
if
(
fichierDestination ==
null
){
JOptionPane.showMessageDialog
(
CopieFichierModeGraphique.this
,
"Veuillez selectionner un fichier destination."
,
"Selection incomplete"
,
JOptionPane.ERROR_MESSAGE
);
return
;
}
try
{
copier
(
fichierSource.getAbsolutePath
(
),
fichierDestination.getAbsolutePath
(
));
JOptionPane.showMessageDialog
(
CopieFichierModeGraphique.this
, "Le fichier a ete copie avec success."
);
}
catch
(
FileNotFoundException e) {
e.printStackTrace
(
);
JOptionPane.showMessageDialog
(
CopieFichierModeGraphique.this
, e.getMessage
(
),
"Fichier non trouve"
, JOptionPane.ERROR_MESSAGE);
}
catch
(
IOException e) {
e.printStackTrace
(
);
JOptionPane.showMessageDialog
(
CopieFichierModeGraphique.this
, e.getMessage
(
),
"Erreur de lecture/ecriture diverse"
, JOptionPane.ERROR_MESSAGE);
}
}
}
boutonCopier.addActionListener
(
new
ActionBoutonCopier
(
));
add
(
boutonCopier);
add
(
new
JLabel
(
));
pack
(
);
setLocationRelativeTo
(
null
);
}
public
static
void
main
(
String[] args) {
new
CopieFichierModeGraphique
(
).setVisible
(
true
);
}
public
void
copier
(
String source, String destination)
throws
FileNotFoundException, IOException {
FileInputStream fichierLecture =
null
;
FileOutputStream fichierSauvegarde =
null
;
BufferedInputStream tamponFichierLecture =
null
;
BufferedOutputStream tamponFichierSauvegarde =
null
;
try
{
fichierLecture =
new
FileInputStream
(
source);
tamponFichierLecture =
new
BufferedInputStream
(
fichierLecture);
fichierSauvegarde =
new
FileOutputStream
(
destination);
tamponFichierSauvegarde =
new
BufferedOutputStream
(
fichierSauvegarde);
while
(
true
){
int
valeurEntiereOctet =
tamponFichierLecture.read
(
);
if
(
valeurEntiereOctet ==
-
1
)
break
;
tamponFichierSauvegarde.write
(
valeurEntiereOctet);
}
}
catch
(
FileNotFoundException e) {
e.printStackTrace
(
);
String [] motsDuMessage =
e.getMessage
(
).split
(
" "
);
String message =
"Impossible d'ouvrir le fichier "
+
motsDuMessage[0
]+
" ."
+
"
\n
Verifiez que le fichier existe et qu'il ne s'agisse pas"
+
" du tout d'un repertoire."
;
throw
new
FileNotFoundException
(
message);
}
catch
(
IOException e) {
e.printStackTrace
(
);
String message =
"Un erreur de lecture ou d'ecriture diverse est survenue."
;
throw
new
IOException
(
message);
}
finally
{
try
{
tamponFichierSauvegarde.flush
(
);
tamponFichierLecture.close
(
);
fichierLecture.close
(
);
tamponFichierSauvegarde.close
(
);
fichierSauvegarde.close
(
);
}
catch
(
IOException exception){
exception.printStackTrace
(
);
}
}
}
}