« Bonjour, Amigo ! Aujourd'hui, nous allons une fois de plus nous pencher sur le fonctionnement d'InputStream et OutputStream. L'explication initiale était en fait un peu simpliste. Ce ne sont pas des interfaces. Ce sont des classes abstraites, et elles ont même quelques méthodes implémentées. Découvrons les méthodes qu'elles possèdent : »

Méthodes d'InputStream Ce que la méthode fait
int read(byte[] buff);
Cette méthode lit immédiatement un bloc d'octets dans le tampon (tableau d'octets), jusqu'à ce que le tampon soit plein ou jusqu'à ce que la source n'ait plus d'octets à lire.
La méthode renvoie le nombre d'octets réellement lus (qui peut être inférieur à la longueur du tableau)
int read();
Cette méthode lit un octet et le renvoie. Le résultat est élargi en int à des fins cosmétiques. S'il n'y a plus d'octets à lire, la méthode renvoie -1.
int available();
Cette méthode renvoie le nombre d'octets non lus (disponibles).
void close();
Cette méthode « ferme » le flux. Tu peux l'appeler quand tu as fini de travailler avec le flux.
L'objet effectue alors les opérations d'entretien nécessaires pour fermer le fichier, etc.
À ce stade, tu ne peux plus lire de données à partir du flux.

« Donc on peut lire non seulement des octets, mais aussi des blocs entiers ? »

« Exactement. »

« Peut-on aussi écrire des blocs entiers ? »

« Oui, regarde un peu. »

Méthodes d'OutputStream Ce que la méthode fait
void write(int c);
Cette méthode écrit un octet. Le type int est réduit en byte. La partie supplémentaire est tout simplement abandonnée.
void write(byte[] buff);
Cette méthode écrit un bloc d'octets.
void write(byte[] buff, int from, int count);
Cette méthode écrit une partie d'un bloc d'octets. Elle est utilisée dans les cas où le tableau d'octets peut ne pas avoir été entièrement rempli.
void flush();
Si le flux stocke en interne des données qui n'ont pas encore été écrites, la méthode force leur écriture.
void close();
Cette méthode « ferme » le flux. Tu peux l'appeler quand tu as fini de travailler avec le flux.
L'objet effectue alors les opérations d'entretien nécessaires pour fermer le fichier, etc. Tu ne peux plus écrire des données sur le flux, et la méthode flush est appelée automatiquement.

« À quoi ressemblerait le code de copie de fichier si on lisait des blocs entiers à la fois au lieu d'octets uniques ? »

« Hmm. Quelque chose comme ceci : »

Copier un fichier sur le disque
public static void main(String[] args) throws Exception
{
 //Create a stream to read bytes from a file
 FileInputStream inputStream = new FileInputStream("c:/data.txt");
 //Create a stream to write bytes to a file
 FileOutputStream outputStream = new FileOutputStream("c:/result.txt");

  byte[] buffer = new byte[1000];
 while (inputStream.available() > 0) //as long as there are unread bytes
 {
  //Read the next block of bytes into buffer, and store the actual number of bytes read in count.
  int count = inputStream.read(buffer);
  outputStream.write(buffer, 0, count); //Write a block (part of a block) to the second stream
 }

 inputStream.close(); //Close both streams. We don't need them any more.
 outputStream.close();
}

« J'ai tout compris au sujet du tampon, mais c'est quoi, la variable count ? »

« Quand on lit le dernier bloc de données d'un fichier, on peut se retrouver avec, mettons, 328 octets au lieu de 1000. Ainsi, lorsque nous écrivons les données, nous devons indiquer que nous n'écrivons pas le bloc entier : seulement ses 328 premiers octets. »

Quand nous lisons le dernier bloc, la méthode read renvoie le nombre d'octets effectivement lus. 1000 chaque fois que nous lisons un bloc, à l'exception du dernier bloc, pour lequel nous n'avons que 328 octets.

Ainsi, lorsque nous écrivons un bloc, nous indiquons que tous les octets dans la mémoire tampon ne doivent pas être écrits, juste les 328 premiers (la valeur stockée dans count).

« À présent, tout est clair. Merci, Ellie. »