"Salut ! Dans la leçon d'aujourd'hui, nous poursuivrons notre conversation sur les flux d'entrée et de sortie en Java ( Java I/O ). Ce n'est pas la première leçon sur ce sujet, et ce ne sera certainement pas la dernière :) Entrée/sortie en Java.  Classes FileInputStream, FileOutputStream et BufferedInputStream - 1Comme il se produit, le langage Java offre de nombreuses façons de travailler avec les E / S. Il existe de nombreuses classes qui implémentent cette fonctionnalité, nous les avons donc divisées en plusieurs leçons - afin que vous ne soyez pas confus dès le début :) Dans le passé leçons, nous avons abordé BufferedReader, ainsi que les classes InputStreamet OutputStreamabstract et plusieurs descendants. Aujourd'hui, nous allons considérer 3 nouvelles classes : FileInputStream,  FileOutputStream, et  BufferedInputStream.

La classe FileOutputStream

Le but principal de la FileOutputStreamclasse est d'écrire des octets dans un fichier. Rien de compliqué :) FileOutputStreamest l'une des implémentations de la OutputStreamclasse abstraite. Dans le constructeur, les objets de cette classe prennent soit le chemin vers le fichier cible (où les octets doivent être écrits), soit un Fileobjet. Nous examinerons des exemples de chacun :

public class Main { 

   public static void main(String[] args) throws IOException { 

       File file = new File("C:\\Users\\Username\\Desktop\\test.txt"); 
       FileOutputStream fileOutputStream = new FileOutputStream(file); 

       String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!"; 

       fileOutputStream.write(greetings.getBytes()); 
       fileOutputStream.close(); 
   } 
}
Lors de la création de l' Fileobjet, nous avons passé le chemin souhaité au constructeur. Nous n'avons pas besoin de le créer à l'avance : s'il n'existe pas, le programme le créera. Vous pouvez également vous débrouiller sans créer d'objet supplémentaire, en passant simplement une chaîne avec le chemin :

public class Main { 

    public static void main(String[] args) throws IOException { 

       FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt"); 
       String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!"; 

       fileOutputStream.write(greetings.getBytes()); 
       fileOutputStream.close(); 
   } 
} 
Le résultat dans les deux cas sera le même. Nous pouvons ouvrir notre fichier et y voir ce qui suit :

Hi! Welcome to CodeGym — The best site for would-be programmers!
Mais il y a une nuance ici. Essayez d'exécuter le code de l'exemple ci-dessus plusieurs fois de suite. Regardez ensuite dans le fichier et répondez à cette question : combien de lignes contient-il ? Juste un. Mais vous avez exécuté le code plusieurs fois. Il s'avère que les données sont écrasées à chaque fois - l'ancienne est remplacée par la nouvelle. Que faire si cela ne nous convient pas et que nous devons écrire séquentiellement dans le fichier ? Que se passe-t-il si nous voulons écrire notre message d'accueil dans un fichier trois fois de suite ? Tout est très simple. Étant donné que le langage ne peut pas savoir de quel comportement nous avons besoin dans chaque cas, le FileOutputStreamconstructeur peut prendre un paramètre supplémentaire —boolean append. Si sa valeur est true, les données seront écrites à la fin du fichier. S'il est faux (et par défaut, il est faux), toutes les anciennes données seront effacées et remplacées par de nouvelles données. Vérifions cela en exécutant notre code modifié trois fois :

public class Main { 

   public static void main(String[] args) throws IOException { 

       FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt", true); 
       String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!\r\n"; 

       fileOutputStream.write(greetings.getBytes()); 
       fileOutputStream.close(); 
   } 
} 
Contenu du fichier :

Hi! Welcome to CodeGym — The best site for would-be programmers! 
Hi! Welcome to CodeGym — The best site for would-be programmers! 
Hi! Welcome to CodeGym — The best site for would-be programmers!
Maintenant c'est différent ! N'oubliez pas cette fonctionnalité lorsque vous utilisez des classes d'E/S. Il fut un temps où je passais des heures sur des tâches, me creusant la cervelle pendant des heures, essayant de comprendre comment mes données disparaissaient des fichiers :) Et bien sûr, tout comme avec les autres classes I/O, n'oubliez pas d'utiliser la close()méthode pour libérer des ressources.

La classe FileInputStream

Le FileInputStreama le but opposé - lire des octets à partir d'un fichier. Tout comme FileOutputStreaminherits OutputStream, cette classe dérive de la InputStreamclasse abstraite. Nous allons écrire quelques lignes de texte dans notre fichier " test.txt " :

"So close no matter how far 
Couldn't be much more from the heart 
Forever trusting who we are 
And nothing else matters"
Entrée/sortie en Java.  Classes FileInputStream, FileOutputStream et BufferedInputStream - 2Voici à quoi ressemble la lecture des données d'un fichier en utilisant FileInputStream:

public class Main { 

   public static void main(String[] args) throws IOException { 

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt"); 

       int i; 

       while((i=fileInputStream.read())!= -1){ 

           System.out.print((char)i); 

       } 
   } 
}
Nous lisons un octet du fichier, convertissons les octets lus en caractères et les affichons sur la console. Et voici la sortie de la console :

So close no matter how far 
Couldn't be much more from the heart 
Forever trusting who we are 
And nothing else matters

La classe BufferedInputStream

Je pense que, compte tenu des connaissances des leçons précédentes, vous pouvez facilement dire pourquoi nous avons besoin de la BufferedInputStreamclasse et quels avantages elle a par rapport à FileInputStream:) Nous avons déjà rencontré des flux tamponnés, alors essayez de deviner (ou de vous souvenir) avant de continuer à lire :) Les flux tamponnés sont principalement nécessaires pour optimiser les E/S. Accéder à une source de données, comme la lecture d'un fichier, est une opération coûteuse en termes de performances Et accéder à un fichier pour lire chaque octet est du gaspillage. C'est pourquoi BufferedInputStreamlit les données non pas un octet à la fois, mais par blocs, et les stocke temporairement dans un tampon spécial. Cela nous permet d'optimiser le programme en réduisant le nombre de fois que nous accédons au fichier. Voyons à quoi cela ressemble :

public class Main { 

   public static void main(String[] args) throws IOException { 

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt"); 

       BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, 200); 

       int i; 

       while((i = bufferedInputStream.read())!= -1){ 

           System.out.print((char)i); 
       } 
   } 
} 
Ici, nous avons créé un BufferedInputStreamobjet. Son constructeur prend une instance de la InputStreamclasse ou de l'un de ses descendants, il en FileInputStreamva de même. Comme argument supplémentaire, il prend la taille du tampon en octets. Grâce à cet argument, les données seront désormais lues depuis le fichier non pas un octet à la fois, mais 200 octets à la fois ! Imaginez à quel point nous avons réduit le nombre d'accès aux fichiers. Pour comparer les performances, vous pouvez prendre un gros fichier texte (plusieurs mégaoctets de texte) et comparer le temps qu'il faut en millisecondes pour lire et sortir sur la console en utilisant FileInputStreamet BufferedInputStream. Voici le code qui illustre les deux options :

public class Main { 

   public static void main(String[] args) throws IOException { 

       Date date = new Date(); 

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\textBook.rtf"); 
       BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); 

       int i; 
       while((i = bufferedInputStream.read())!= -1){ 

           System.out.print((char)i); 
       } 

       Date date1 = new Date(); 
       System.out.println((date1.getTime() - date.getTime())); 
   } 
} 

 
public class Main { 

   public static void main(String[] args) throws IOException { 

       Date date = new Date(); 
       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\26951280.rtf"); 

       int i; 
       while((i = fileInputStream.read())!= -1){ 

           System.out.print((char)i); 
       } 


       Date date1 = new Date(); 
       System.out.println((date1.getTime() - date.getTime())); 
   }
}
Lors de la lecture d'un fichier de 1,5 Mo sur mon ordinateur, FileInputStreamj'ai terminé le travail en ~ 3500 millisecondes, mais BufferedInputStreamje l'ai géré en ~ 1700 millisecondes. Comme vous pouvez le voir, le flux tamponné a optimisé le travail, le coupant de moitié ! :) Nous continuerons à étudier les classes I/O — à bientôt !