Notes S10
Synthèse du cours : Entrées/sorties (CS-108)
1. Concepts fondamentaux
Les entrées/sorties (E/S) désignent les échanges de données entre un programme et l’extérieur : utilisateur (console), fichiers ou réseau. Un fichier est une séquence d’octets stockée sur un support physique, accompagnée de méta-données (nom, droits, date). Un système de fichiers organise ces fichiers dans une arborescence de dossiers, où chaque élément est désigné par un chemin d’accès (séparateur / sous Unix, \ sous Windows).
On distingue deux types de fichiers : textuels (séquence de caractères) et binaires (tous les autres), même si techniquement tout fichier est une suite d’octets.
2. Les flots en Java
La bibliothèque Java propose deux paquetages : java.io (basé sur les flots/streams) et java.nio (basé sur les mémoires tampons/buffers, plus performant). Le cours se concentre sur java.io.
Un flot est une séquence de valeurs accédées séquentiellement. Quatre hiérarchies existent selon le sens et le type de données :
| Entrée | Sortie | |
|---|---|---|
| Octets | InputStream | OutputStream |
| Caractères | Reader | Writer |
3. Flots d’octets
InputStream — méthodes principales
read(): lit un octet (0-255, ou -1 en fin de flot)readNBytes(...),readAllBytes(): lecture par blocstransferTo(OutputStream): transfert vers un flot de sortieskip(),available(): ignorer / estimer les octets disponiblesmark()/reset(): marquer une position et y revenirclose(): fermeture indispensable pour libérer les ressources système
⚠️ Piège important : read() retourne un int entre 0 et 255, mais lorsqu’on lit dans un byte[], les valeurs vont de -128 à +127 (le -1 n’y signifie plus la fin du flot !).
Sous-classes concrètes
- Primaires :
FileInputStream(fichier),ByteArrayInputStream(tableau) - Filtrantes :
BufferedInputStream(mémoire tampon, améliore les performances),GZIPInputStream(décompression à la volée)
Les flots peuvent être empilés. Exemple typique pour lire un fichier compressé :
new GZIPInputStream(
new BufferedInputStream(
new FileInputStream("in.gz")));OutputStream
Symétrique d’InputStream avec write() (3 variantes) et flush() (force l’écriture effective). PrintStream ajoute print, println, printf — c’est le type de System.out et System.err.
4. Gestion des ressources : try-with-resources
Les flots étant liés à des ressources système, leur fermeture est cruciale. Le try-with-resources garantit l’appel automatique de close() :
java
try (InputStream s = new FileInputStream(...)) { // utilisation } // close() appelé automatiquement
Cela fonctionne pour toute classe implémentant l’interface AutoCloseable.
5. Représentation des caractères
Évolution historique
- ASCII (7 bits, 128 caractères) : adapté à l’anglais uniquement
- Extensions 8 bits (ISO 8859-1, Windows 1252…) : régionales
- Unicode : standard universel visant à représenter tous les caractères
Les encodages Unicode
- UTF-8 : taille variable (1 à 4 octets), compatible ASCII, le plus populaire
- UTF-16 : 2 ou 4 octets
- UTF-32 : taille fixe (4 octets)
Pour la chaîne « œuf à €1 » : 12 octets en UTF-8, 16 en UTF-16, 32 en UTF-32.
En Java
Le type char fait 16 bits (héritage historique d’Unicode). Une String est en réalité une séquence d’unités UTF-16. Conséquence : les caractères au-delà de FFFF₁₆ (comme les émojis 👍) occupent deux « caractères » Java. Ainsi :
"\uD83D\uDC4D".length() // 2
"\uD83D\uDC4D".codePointCount(0, 2) // 16. Entrées/sorties textuelles
Un fichier textuel est une séquence de caractères encodés. ⚠️ L’encodage n’est généralement pas stocké dans le fichier — il faut le connaître ou le deviner. La séquence 62 c5 93 75 66 peut donner « bœuf » (UTF-8) ou « bÅ uf » (ISO 8859-1) selon l’interprétation.
Trois représentations de fin de ligne coexistent : CR (ancien macOS), LF (Unix/Linux/macOS moderne), CRLF (Windows).
Reader et Writer
Équivalents caractères de InputStream/OutputStream. Différence : Reader n’a pas available() mais ready() (car décoder des octets coûte cher).
Classes principales
FileReader/FileWriter: fichiers (avec encodage en argument)InputStreamReader/OutputStreamWriter: passerelles entre flots d’octets et flots de caractèresBufferedReaderajoutereadLine(),BufferedWriterajoutenewLine()LineNumberReader: suit le numéro de ligne courant
Exemple de conversion d’encodage
try (Reader i = new FileReader("utf8.txt", StandardCharsets.UTF_8);
Writer o = new FileWriter("utf16.txt", StandardCharsets.UTF_16)) {
i.transferTo(o);
}Points clés à retenir
- Toujours fermer les flots — utiliser
try-with-resources - Empilage de flots : la classe
Buffered...améliore presque toujours les performances - Octets vs caractères : deux hiérarchies parallèles (
InputStream/Reader,OutputStream/Writer) - Encodage : toujours le spécifier explicitement pour les fichiers textuels (UTF-8 par défaut recommandé)
- Pièges Unicode en Java :
length()ne donne pas le nombre de caractères Unicode pour les chaînes contenant des émojis ou caractères hors BMP