"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 :) Comme 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 InputStream
et OutputStream
abstract et plusieurs descendants. Aujourd'hui, nous allons considérer 3 nouvelles classes : FileInputStream
, FileOutputStream
, et BufferedInputStream
.
La classe FileOutputStream
Le but principal de laFileOutputStream
classe est d'écrire des octets dans un fichier. Rien de compliqué :) FileOutputStream
est l'une des implémentations de la OutputStream
classe 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 File
objet. 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' File
objet, 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 FileOutputStream
constructeur 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
LeFileInputStream
a le but opposé - lire des octets à partir d'un fichier. Tout comme FileOutputStream
inherits OutputStream
, cette classe dérive de la InputStream
classe 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"
Voici à 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 laBufferedInputStream
classe 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 BufferedInputStream
lit 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 BufferedInputStream
objet. Son constructeur prend une instance de la InputStream
classe ou de l'un de ses descendants, il en FileInputStream
va 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 FileInputStream
et 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, FileInputStream
j'ai terminé le travail en ~ 3500 millisecondes, mais BufferedInputStream
je 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 !
GO TO FULL VERSION