J'ai trouvé un article quelque part avant que la définition de FileInputStream sur BufferedStream accélère le processus. Donc cette fois, j'écrirai un article sur FileInputStream et BufferedInputStream.
2019/10/06 postscript Dans le commentaire, il a expliqué pourquoi la vitesse de traitement est augmentée même avec FileInputStream lors de l'utilisation d'InputStreamReader. Veuillez vous y référer.
La différence entre les deux était facile à comprendre en lisant ce qui suit.
Il s'agit d'un appel natif au système d'exploitation qui utilise le disque pour lire 1 octet. C'est une opération lourde.
Avec> BufferedInputStream, cette méthode délègue à une méthode read () surchargée qui lit 8192 octets et les met en mémoire tampon jusqu'à ce que cela soit nécessaire. Seul 1 octet est toujours retourné (bien que les autres octets soient réservés). De cette manière, BufferedInputStream lit le fichier avec moins d'appels natifs vers le système d'exploitation.
En d'autres termes, FileInputStream ne lit qu'un octet à la fois, ce qui entraîne beaucoup d'accès au disque, tandis que BufferedInputStream lit un grand nombre d'octets à la fois, de sorte que les données peuvent être lues avec moins d'accès au disque. est.
Les résultats de l'expérience réelle sont les suivants. Commencez par créer un fichier à lire comme suit.
Lisez le fichier créé comme suit
final FileOutputStream fos = new FileOutputStream(filePath);
final BufferedOutputStream bos = new BufferedOutputStream(fos);
final OutputStreamWriter osw = new OutputStreamWriter(bos, Charset.defaultCharset());
final PrintWriter pr = new PrintWriter(osw);
for (int i = 0; i < 500000; i++) {
pr.println("Ah");
}
pr.close();
Après avoir lu le fichier ci-dessus avec FileInputStream comme processus 1, j'ai effectué le processus d'ajout de la lecture à StringBuilder.
Processus 1_FileInputStream
//FileInputStream
StringBuilder sb = new StringBuilder();
final FileInputStream inputStream = new FileInputStream(filePath);
//En traitement
long startTime = System.currentTimeMillis();
int line;
while (true) {
line = inputStream.read();
if (line == -1) {
break;
}
sb.append(line);
}
long endTime = System.currentTimeMillis();
System.out.println("temps de traitement: " + (endTime - startTime));
inputStream.close();
Dans le processus 2, FileInputStream a été encapsulé dans BufferedInputStream et utilisé.
Processus 2_BufferedInputStream
//BufferedInputStream
StringBuilder sb = new StringBuilder();
final FileInputStream fis = new FileInputStream(filePath);
BufferedInputStream inputStream = new BufferedInputStream(fis);
//En traitement
long startTime = System.currentTimeMillis();
int line;
while (true) {
line = inputStream.read();
if (line == -1) {
break;
}
sb.append(line);
}
long endTime = System.currentTimeMillis();
System.out.println("temps de traitement: " + (endTime - startTime));
inputStream.close();
fis.close();
Le résultat est le suivant (l'unité est la ms). FileInputStream Première fois: 3840 Deuxième fois: 3820 Troisième fois: 3772
BufferedInputStream 1ère fois: 109 Deuxième fois: 111 Troisième fois: 117
C'est évident en un coup d'œil. De toute évidence, BufferedInputStream est plus rapide. À propos, lorsque le nombre d'instructions For était défini sur 50, il était de 2761196ns pour FileInputStream et de 2198539ns pour BufferedInputStream, qui ne sont pas très différents.
La classe InputStreamReader est utilisée pour convertir la chaîne d'octets du fichier lu en caractères, mais en fait, il s'est avéré que la différence entre FileInputStream et BufferedInputStream est presque éliminée en utilisant InputStreamReader.
Processus 3_FileInputStream+InputStreamReader
//FileInputStream + InputStreamReader
StringBuilder sb = new StringBuilder();
final FileInputStream inputStream = new FileInputStream(filePath);
final InputStreamReader reader = new InputStreamReader(inputStream);
//En traitement
long startTime = System.currentTimeMillis();
int line;
while (true) {
line = reader.read();
if (line == -1) {
break;
}
sb.append(line);
}
long endTime = System.currentTimeMillis();
System.out.println("temps de traitement: " + (endTime - startTime));
inputStream.close();
reader.close();
Processus 4_BufferdInputStream+InputStreamReader
//BufferdInputStream + InputStreamReader
StringBuilder sb = new StringBuilder();
final FileInputStream inputStream = new FileInputStream(filePath);
final BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
final InputStreamReader reader = new InputStreamReader(bufferedInputStream);
//En traitement
long startTime = System.currentTimeMillis();
int line;
while (true) {
line = reader.read();
if (line == -1) {
break;
}
sb.append(line);
}
long endTime = System.currentTimeMillis();
System.out.println("temps de traitement: " + (endTime - startTime));
inputStream.close();
reader.close();
Le résultat est le suivant (l'unité est la ms). FileInputStream + InputStreamReader Première fois: 114 Deuxième fois: 131 Troisième fois: 154
BufferedInputStream + InputStreamReader Première fois: 163 Deuxième fois: 167 Troisième fois: 150
Peut-être parce qu'il est temps de créer une instance de BufferedInputStream, en regardant uniquement les résultats, il semble plus rapide de lire le fichier sans encapsuler FileInputStream lors de l'utilisation d'InputStreamReader.
Si vous voulez sortir le fichier lu sous forme de chaîne de caractères vers StringBuilder etc., vous utiliserez probablement InputStreamReader, donc cela signifie qu'il n'y a pas beaucoup de différence entre FileInputStream et BufferedInputStream. Voir ci-dessous pour une description de InputStreamReader.
・ Qu'est-ce que InputStreamReader: JavaA2Z
De toute évidence, BufferedInputStream est plus rapide, vous pourriez donc penser qu'il vaut mieux l'utiliser, mais il y a des cas où son utilisation n'est pas très efficace.
C'est à ce moment que la taille du tampon est définie dans l'argument de la méthode read. Dans InputStream, la taille de la mémoire tampon peut être définie comme un argument de read (), et il est possible de contrôler le nombre d'octets lus à la fois. Si rien n'est défini, il lira un octet à la fois (à l'exception de BufferedInputStream).
Ainsi, par exemple, si vous réécrivez le code du processus 1 et du processus 2 ci-dessus comme suit, en termes de vitesse, cela ne changera pas beaucoup.
Lecture du processus 1()Essayez de spécifier la taille du tampon dans
//Processus 1 FileInputStream
StringBuilder sb = new StringBuilder();
final FileInputStream inputStream = new FileInputStream(filePath);
// BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
long startTime = System.currentTimeMillis();
int line;
while (true) {
line = inputStream.read(new byte[8192]);
if (line == -1) {
break;
}
sb.append(line);
}
long endTime = System.currentTimeMillis();
System.out.println("temps de traitement: " + (endTime - startTime));
inputStream.close();
Lorsque le traitement était effectué avec FileInputStream et BufferedInputStream en lecture (nouvel octet [8192]), le temps d'exécution pour les deux était de 3 ms, et par conséquent, la vitesse n'a pas beaucoup changé.
Je vais citer ceci car la description sur le site suivant a été utile.
Cela a du sens si vous êtes susceptible d'effectuer un grand nombre de petites lectures (un ou plusieurs octets à la fois), ou si vous souhaitez utiliser le haut niveau de fonctionnalité fourni par l'API Buffer. Par exemple, la méthode BufferedReader.readLine ().
Cependant, si vous utilisez les méthodes read (byte []) ou read (byte [], int, int) pour lire uniquement de gros blocs, encapsuler le InputStream avec un BufferedInputStream n'a aucun effet.
java - Dois-je toujours envelopper le InputStream en tant que BufferedInputStream
Après cela, comme mentionné ci-dessus, même si la taille du fichier d'entrée est extrêmement petite, l'effet de l'habillage est faible car la vitesse ne change pas beaucoup, quel que soit celui utilisé.
Avant d'écrire cet article, je pensais que BufferedInputStream serait absolument plus rapide que FileInputStream, mais lorsque j'ai utilisé InputStreamReader (BufferedInputSteramReader), j'ai trouvé que les deux ne sont pas si différents.
J'ai également appris qu'il existe des cas où l'utilisation de BufferedInputStream n'est pas très efficace.
Comme pour toute classe, il semble important de choisir la bonne classe pour chaque occasion.
Autre référence: Expérimentez la puissance de BufferedInputStream Lors de la lecture de données dans un tableau à l'aide de FIO10-J. Read (), assurez-vous que la lecture dans le tableau a été effectuée comme prévu /fio10-j.html)
Recommended Posts