1. Hiérarchie des exceptions d’E/S
En Java, lors du travail avec des fichiers et d’autres ressources externes, on est presque toujours confronté aux exceptions d’entrée/sortie. Ce sont des objets déclenchés (throw) quand quelque chose se passe mal pendant la lecture ou l’écriture de données. Par exemple, si le fichier est introuvable, si l’accès est refusé ou si le disque s’est soudainement « fatigué ».
Les protagonistes de notre leçon
En Java, il existe toute une hiérarchie de telles exceptions. Voici les principales :
- IOException — la classe de base pour toutes les erreurs d’E/S. Si quelque chose s’est mal passé avec les fichiers, les flux ou le réseau — presque toujours, c’est elle la « coupable » (ou l’un de ses nombreux descendants).
- FileNotFoundException — le « fils » de IOException, qui apparaît lorsque vous essayez d’ouvrir un fichier qui n’existe pas ou si le chemin est incorrect.
Autres dérivés :
- EOFException — également un « fils » direct de IOException. Elle signale que, lors de la lecture, nous avons atteint la fin du fichier de manière inattendue.
- MalformedInputException — un « petit-fils » : il hérite de CharacterCodingException, qui lui-même hérite de IOException. Cette erreur survient si le fichier ne peut pas être correctement interprété avec l’encodage indiqué (par exemple, on attendait "UTF-8", mais une séquence corrompue est arrivée).
- Il y a aussi SocketException, ZipException et d’autres « parents » spécialisés, chacun avec son domaine de responsabilité. Plus on descend dans la hiérarchie, plus la situation est étroite et spécifique.
Petit schéma simplifié :
java.lang.Exception
└── java.io.IOException
├── java.io.FileNotFoundException
├── java.io.EOFException
├── java.nio.charset.MalformedInputException
└── ... (autres)
Fait intéressant :
En Java, presque toutes les opérations avec des fichiers exigent de déclarer ou de gérer IOException — ce sont des exceptions vérifiées (checked). Le compilateur ne vous laissera pas oublier la gestion des erreurs !
2. Quand et pourquoi ces exceptions surviennent
Ouverture d’un fichier inexistant
Le cas le plus fréquent — vous essayez d’ouvrir un fichier, mais il n’existe pas. C’est comme arriver à un arrêt de bus, alors que ce bus n’existe même pas dans l’horaire.
FileInputStream fis = new FileInputStream("abracadabra.txt"); // Boum ! FileNotFoundException
Tentative d’écriture dans un fichier sans droits
Si vous essayez d’écrire un fichier dans un dossier où vous n’avez pas les droits, vous obtiendrez FileNotFoundException ou IOException (selon la situation).
FileOutputStream fos = new FileOutputStream("/system/secret.txt"); // Boum ! FileNotFoundException ou IOException
Erreurs de lecture/écriture dues à un support défectueux
Parfois, le fichier semble exister, mais le disque est endommagé, le fichier est utilisé par un autre programme ou l’électricité a été coupée — vous obtiendrez alors une IOException avec différents messages.
Autres causes
- Le fichier est en lecture seule et vous essayez d’écrire.
- Le chemin du fichier est trop long ou contient des caractères non autorisés.
- Le fichier est utilisé par un autre processus.
- Le disque est plein.
- Le fichier a été supprimé par un autre processus entre la vérification et l’utilisation.
3. Gestion avec try-catch
Chaque fois que vous travaillez avec des fichiers, des flux, le réseau — utilisez try-catch. C’est comme un airbag : si quelque chose se passe mal, le programme ne plantera pas et pourra réagir correctement.
Comment attraper correctement les exceptions ?
En Java, il faut intercepter les exceptions plus spécifiques avant les générales. Si vous placez un catch général (IOException e) en premier, les plus spécifiques, comme FileNotFoundException, ne seront jamais atteintes.
Structure correcte :
try {
// Travail avec le fichier
} catch (FileNotFoundException e) {
// Traitement de la situation « fichier introuvable »
} catch (IOException e) {
// Traitement des autres erreurs d’E/S
}
Pourquoi ?
Parce que FileNotFoundException est un cas particulier de IOException. Si vous attrapez le cas général plus tôt, le cas particulier n’atteindra pas son catch.
Exemple de code : gestion des erreurs lors de l’ouverture d’un fichier
import java.io.*;
public class FileReaderExample {
public static void main(String[] args) {
String filename = "notes.txt";
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
String line = reader.readLine();
System.out.println("Première ligne du fichier: " + line);
reader.close();
} catch (FileNotFoundException e) {
System.out.println("Fichier introuvable: " + filename);
} catch (IOException e) {
System.out.println("Erreur lors de la lecture du fichier: " + e.getMessage());
}
}
}
À noter :
Même si vous avez vérifié que le fichier existe, gardez toujours try-catch — le fichier peut disparaître à tout moment (par exemple, s’il est supprimé par un autre processus).
4. Pratique : écrire du code avec gestion des erreurs
Créons de petits exemples et faisons en sorte qu’ils réagissent correctement à l’absence de fichier et à d’autres erreurs.
Étape 1 : essayons d’ouvrir un fichier inexistant
import java.io.*;
public class NotesApp {
public static void main(String[] args) {
String filename = "my_notes.txt";
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
String line;
System.out.println("Vos notes:");
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
} catch (FileNotFoundException e) {
System.out.println("Oups ! Le fichier de notes est introuvable: " + filename);
System.out.println("Conseil: créez le fichier ou vérifiez son nom.");
} catch (IOException e) {
System.out.println("Une erreur s'est produite lors de la lecture du fichier: " + e.getMessage());
}
}
}
Étape 2 : ajoutons la gestion pour l’écriture du fichier
import java.io.*;
public class NotesWriter {
public static void main(String[] args) {
String filename = "my_notes.txt";
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(filename, true)); // append: true
writer.write("Nouvelle note !\n");
writer.close();
System.out.println("La note a été ajoutée avec succès !");
} catch (IOException e) {
System.out.println("Erreur lors de l'écriture dans le fichier: " + e.getMessage());
}
}
}
Étape 3 : exemple universel avec journalisation des erreurs
import java.io.*;
public class SafeFileCopier {
public static void main(String[] args) {
String source = "source.txt";
String target = "target.txt";
try {
BufferedReader reader = new BufferedReader(new FileReader(source));
BufferedWriter writer = new BufferedWriter(new FileWriter(target));
String line;
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.newLine();
}
reader.close();
writer.close();
System.out.println("Fichier copié avec succès !");
} catch (FileNotFoundException e) {
System.out.println("Fichier introuvable: " + e.getMessage());
} catch (IOException e) {
System.out.println("Erreur d'E/S: " + e.getMessage());
}
}
}
Conseil :
Dans les applications réelles, il vaut mieux journaliser les erreurs non seulement à l’écran, mais aussi dans un fichier ou un journal, afin de pouvoir ensuite comprendre ce qui n’a pas fonctionné.
5. Tableau : principales exceptions d’E/S
| Exception | Quand survient-elle ? | Comment la traiter ? |
|---|---|---|
|
Fichier introuvable, chemin inexistant, droits manquants | Informer l’utilisateur, vérifier le chemin/les droits, créer le fichier si nécessaire |
|
Fin de fichier inattendue lors de la lecture | Signaler une corruption/incomplétude, tenter de restaurer partiellement les données |
|
Erreur d’E/S générale (disque, droits, verrouillage) | Vérifier les détails, terminer l’opération proprement, réessayer si possible |
|
Encodage ou structure de fichier incorrects | Signaler une corruption, essayer un autre encodage/source |
6. Erreurs typiques lors de la gestion des exceptions d’E/S
Erreur n°1 : n’attraper que l’Exception générale. Il est très tentant d’écrire simplement catch (Exception e), mais vous ne pourrez alors pas distinguer ce qui a réellement mal tourné. Mieux vaut d’abord intercepter les exceptions spécifiques (FileNotFoundException), puis — l’IOException générale.
Erreur n°2 : ne pas fermer les flux en cas d’erreur. Si vous avez ouvert un fichier et qu’une exception survient ensuite, le flux peut rester ouvert. Utilisez try-with-resources ou fermez les ressources dans finally.
Erreur n°3 : ignorer les messages des exceptions. N’affichez pas simplement « Erreur ! », mais montrez des détails : e.getMessage(). Cela aidera à comprendre plus rapidement ce qui s’est mal passé.
Erreur n°4 : ne pas traiter FileNotFoundException lors de l’écriture. Beaucoup pensent que FileNotFoundException concerne uniquement la lecture. En réalité, elle peut aussi survenir à l’écriture (chemin incorrect, pas de droits pour créer le fichier, etc.).
Erreur n°5 : ne pas vérifier les droits d’accès. Si le programme est lancé avec des droits limités, de nombreuses opérations sur les fichiers peuvent échouer. Tenez-en toujours compte et informez l’utilisateur.
GO TO FULL VERSION