« Bonjour, Amigo ! Aujourd'hui, nous allons faire connaissance avec les flux d'entrée/sortie. Nous avons survolé ce sujet il y a quelques jours, mais aujourd'hui, nous allons l'explorer en profondeur. Les flux d'entrée/sortie sont répartis en 4 catégories : »

1) Les flux sont divisés selon leur direction : flux d'entrée ou flux de sortie

2) Les flux sont aussi divisés en fonction de leur type de données : ceux qui travaillent avec des octets et ceux qui travaillent avec des caractères.

Ici, ces divisions sont présentées dans un tableau :

Flux d'entrée Flux de sortie
Travaille avec des octets InputStream OutputStream
Travaille avec des caractères Reader Writer

Si un objet implémente l'interface InputStream, il prend en charge la capacité de lire des octets séquentiellement.

Si un objet implémente l'interface OutputStream, il prend en charge la capacité d'écrire des octets séquentiellement.

Si un objet implémente l'interface Reader, il prend en charge la capacité de lire des caractères (char) avec.

Si un objet implémente l'interface Writer, il prend en charge la capacité d'écrire des caractères (char) avec.

Flux d'entrée/sortie - 1

Un flux de sortie est comme une imprimante. On peut envoyer des documents à une imprimante. On peut envoyer des données à un flux de sortie.

Pour sa part, un flux d'entrée peut être comparé à un scanner, ou peut-être à une prise électrique. Avec un scanner, on peut importer des documents sur un ordinateur. Ou on peut brancher un appareil sur une prise électrique pour recevoir de l'électricité. On peut recevoir des données depuis un flux d'entrée.

« Où sont-ils utilisés ? »

« Les flux sont utilisés partout en Java. Notre cher ami System.in est une variable static InputStream nommée in dans la classe System. »

« Sans blague !? Je me servais d'un InputStream depuis le début et je ne le savais même pas. System.out est aussi un flux alors ? »

« Oui, System.out est une variable static PrintStream (descendant d'OutputStream) dans la classe System. »

« Tu es en train de me dire que j'ai toujours utilisé des flux sans même le savoir ? »

« Oui, et ça montre combien ces flux sont pratiques. Il te suffit d'en prendre un et de l'utiliser. »

« Mais on ne peut pas dire ça pour System.in. Nous avons constamment dû lui ajouter BufferedReader ou InputStreamReader. »

« C'est vrai. Mais il y avait aussi des raisons à cela. »

Il y a beaucoup de types de données, et de nombreuses façons de travailler avec. Ainsi, le nombre de classes d'E/S standard a grandi très rapidement, alors qu'elles faisaient tout leur travail quasiment de la même façon. Pour éviter cette complexité, les développeurs Java ont utilisé le principe d'abstraction et divisé ces classes en plusieurs petites parties.

Mais tu peux connecter ces parties de manière cohérente et obtenir des fonctionnalités très complexes si tu en as besoin. Regarde cet exemple :

Envoi d'une chaîne dans la console
System.out.println("Hello");
Stocke le flux de sortie de la console dans une variable séparée.
Envoie une chaîne dans le flux.
PrintStream console = System.out;
console.println("Hello");
Crée un tableau dynamique (extensible) dans la mémoire.
Connecte-le à un nouveau flux de sortie (objet PrintStream).
Envoie une chaîne dans le flux.
ByteArrayOutputStream stream = new ByteArrayOutputStream();
PrintStream console = new PrintStream(stream);
console.println("Hello");

« Honnêtement, ça me fait plus penser à un jeu de Lego. Sauf que je ne comprends pas du tout ce que ce code fait. »

« Ne t'en soucie pas pour le moment. Chaque chose en son temps. »

Voici ce que je veux que tu retiennes : Si une classe implémente l'interface OutputStream, tu peux écrire des octets dedans. Presque exactement comme tu envoies des données à la console. Ce qu'elle fait avec, c'est sa propre affaire. Avec notre « jeu de Lego », nous ne nous soucions pas du but de chaque partie. Ce qui nous intéresse, c'est le fait que cette grande sélection de pièces nous permet de construire des choses vraiment chouettes.

« OK. Alors par où commencer ? »