IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

avec Java Discussion :

[java.nio] lecture un peu trop lente par rapport à un BufferedReader


Sujet :

avec Java

  1. #1
    Inactif  
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    885
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 885
    Points : 1 320
    Points
    1 320
    Par défaut [java.nio] lecture un peu trop lente par rapport à un BufferedReader
    Bien le bonjour,

    J'ai besoin de lire des lignes dans un fichier, et ce pour des fichiers de toute taille.
    Jusque là j'utilisais un bon vieux BufferedReader, les performances étant au rendez-vous.
    Pour le fun, je me suis mis dans la tête de faire un tour du côté du package java.nio et ses FileChannel, ByteBuffer.
    Pour simplifier mon code, j'ai pondu une classe permettant la lecture de lignes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    package com.grosbidule.gcon4j.util.nio;
     
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
     
     
    public class FastFileReader {
     
        private FileChannel fc;
        private ByteBuffer buffer;
        private StringBuilder line;
        private char c;
     
        public FastFileReader(File f) 
                throws FileNotFoundException,
                       IOException {
            buffer = ByteBuffer.allocate((int)f.length());
            fc = new FileInputStream(f).getChannel();
            fc.read(buffer);
            buffer.rewind();
        }
     
        public void close()
                throws IOException {
            fc.close();
        }
     
        // lecture d'une ligne. Il me faut le même comportement
        // que la méthode readline() d'un BuferedReader.
        public String readLine() {
            if (false == buffer.hasRemaining()) {
                return null;
            }
     
            // prend la moitiée du temps
            line = new StringBuilder();
     
            // la boucle while prend l'autre moitiée du temps
            while (buffer.hasRemaining()) {
                c = (char)buffer.get();
                if ((c == '\n') || (c == '\r')) {
                    break;
                }
                line.append(c);
            }
            return line.toString();
        }
    }
    Ce qui est étrange, c'est que je perds énormément en performances. Par exemple, sur un fichier texte d'environ 700 Ko, un BufferedReader ( et sa méthode readLine() ) demande à peine 1 seconde pour lire 10 fois tout le fichier, alors qu'avec java.nio je passe à plus de 4 secondes.
    Le fichier de test contient des lignes allant de 0 à plus de 10 000 caractères (pour le fun ^^).

    J'ai regardé le tutoriel présent : sur gfx.developpez.com, mais visiblement il y a quelque chose que je dois comprendre de travers, mais quoi ?
    Peut être un problème ailleurs que dans java.nio ..., j'avais pensé à l'affectation de mon StringBuilder dans la méthode readLine, mais elle ne prend "que" la moitié du temps (mais bon ça semble quand même à corriger, et là je bloque aussi). En changeant la taille de mon StringBuilder, je ne fais que perdre en performance.


    En vous remerciant pour vos lumières.
    *graou* et même *graou*, ou encore *graou*

  2. #2
    Membre expérimenté
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Points : 1 419
    Points
    1 419
    Par défaut
    Sans médire, c'est clair que quand on fait soi-même quelque chose, on optimise moins que les gars qui cherchent dessus pendant des plombes ^^

    En fait, c'est simplement ça le problème, c'est que tu ne sais pas comment optimiser ton code.

    Premier problème, CharBuffer existe. Tu tentes de lire du texte (car séparé par (\n|\r\n?) ) dans un fichier binaire. Essaie de passer d'un ByteBuffer à un CharBuffer. Un indice ? java.nio.charset.Charset.decode(ByteBuffer) !

    Deuxième problème, tu utilises un nouveau StringBuilder à chaque recherche de nouvelle ligne (même si la variable en elle-même est d'instance). Utilise sa méthode setLength(0) dessus juste après avoir créé le String. Ca t'aidera grandement. Ensuite, dans ta méthode close,ajoute ceci : "line = null;" histoire de bien vider le buffer de StringBuilder, car son il fera environ 10ko à la fin de la lecture du fichier (peut-être 16ko, voire max 20ko).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public String readLine() {
      if (this.line == null) {
        this.line = new StringBuilder();
      }
      ... // Lecture du buffer
      String retour = this.line.toString();
      this.line.setLength(0); // Réinitialisation du buffer interne de line.
      return retour;
    }
    Troisième problème, tu alloues un buffer de la taille du fichier. Cela veut dire que ton système doit instancier d'un coup un tableau de 700ko. C'est trop. 4 ko est généralement un excellent compromis. Et quand le buffer est vide (n'a plus de caractères à lire), on le remplit à nouveau.

    Ce n'est pas complet, mais en réglant ces petits soucis, tu devrais déjà voir une amélioration des performances.

Discussions similaires

  1. Fonction Java trop lente
    Par haskouse dans le forum Général Java
    Réponses: 17
    Dernier message: 09/08/2011, 15h18
  2. [AC-2003] Requete ACCESS trop lente par rapport a SQL SERVER 2005
    Par apnw7931 dans le forum Requêtes et SQL.
    Réponses: 6
    Dernier message: 07/03/2011, 18h48
  3. Lecture d'un fichier ligne par ligne en Java
    Par Lolitaaa dans le forum Général Java
    Réponses: 5
    Dernier message: 07/07/2010, 11h49
  4. [Java 1.4] : lecture d'un fichier octet par octet
    Par Thi0123 dans le forum Entrée/Sortie
    Réponses: 10
    Dernier message: 08/06/2007, 21h29
  5. Communication Série un peu trop lente?
    Par SimonBrodeur dans le forum VB 6 et antérieur
    Réponses: 22
    Dernier message: 16/01/2006, 14h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo