[JAVA] Résumé de FileInputStream et BufferedInputStream

Aperçu

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.

Quelle est la différence entre les deux?

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.

Pourquoi utiliser BufferedInputStream pour lire des fichiers en octets plus rapidement qu'avec FileInputStream?

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.

Y a-t-il une différence si j'utilise InputStreamReader?

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

Dois-je donc toujours utiliser BufferedInputStream?

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é.

Résumé

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

Résumé de FileInputStream et BufferedInputStream
Un bref résumé des conteneurs DI et DI
Résumé des hachages et symboles dans Ruby
Résumé de Java Math.random et import (calendrier)
[Java] Résumé personnel des classes et méthodes (basique)
Résumé du réglage de l'heure au Japon et de la méthode d'affichage
Résumé des sources OpenJDK
vue d'ensemble du fichier jar
Résumé sur la sécurité de l'information
Résumé de l'utilisation de FragmentArgs
Résumé de l'utilisation de DBFlow
Résumé du support Java 2018
Résumé des commandes fréquemment utilisées dans Rails et Docker
Résumé du comportement de ToString avec les annotations Java et Groovy
Configuration de JMeter et jEnv
Contexte et mécanisme de Fabric-loader
[Java11] Résumé du flux -Avantages du flux-
Résumé de l'utilisation de ButterKnife
[Java] Résumé des expressions régulières
Combinaison de recherche et each_with_index
[Java] Résumé des opérateurs (opérateur)
Jugement de JSONArray et JSONObject
Résumé des "différences d'interface abstraites"
Résumé des bases du langage Java
Résumé de la classe Java Math
Opérateur résiduel et puissance (冪 puissance)
Avantages et inconvénients de Java
Résumé des fonctions de base d'ImageJ
[Java] Résumé de la syntaxe de contrôle
Résumé du traitement des erreurs Java
[Java] Résumé des modèles de conception
[Java] Résumé des opérations mathématiques
[Webpacker] Résumé de l'installation de Bootstrap et jQuery dans Rails 6.0
Résumé des problèmes et des contre-mesures lors de l'utilisation d'IE avec WebDriver de Selenium2
Bases du branchement conditionnel et du retour
[Pour les débutants] Résumé du constructeur java
Date de sortie de Java et résumé EOL
À propos de Biocontainers fastqc et Java
Résumé du package [Java Silver Study]
[Rails] Résumé de la configuration de routage compliquée
Utilisez redirect_to et effectuez un rendu correctement
Résumé de l'état initial du contrôleur de l'appareil
Ceci et cela de JDK
Résumé des commandes Docker fréquemment utilisées
[Swift] Avantages et inconvénients de Storyboard
Utilisation correcte de Mockito et PowerMock
[Rails] Différences et utilisation de each_with_index et each.with_index
À propos de removeAll et de retentionAll de ArrayList
Implémentation par défaut de Object.equals () et Object.hashCode ()
Application des méthodes downcase et slice
Résumé de la programmation orientée objet utilisant Java
Ceci et cela du contrôle exclusif