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

Entrée/Sortie Java Discussion :

Besoin d'optimiser une lecture de fichier


Sujet :

Entrée/Sortie Java

  1. #1
    Membre averti Avatar de BakaOnigiri
    Inscrit en
    Avril 2002
    Messages
    366
    Détails du profil
    Informations forums :
    Inscription : Avril 2002
    Messages : 366
    Points : 437
    Points
    437
    Par défaut Besoin d'optimiser une lecture de fichier
    Bien le bonjour,

    voilà, j'ai une petite question : j'ai une classe qui serte à charger en mémoire un fichier Shape ESRI (je suis sur du développement d'une application de controle de trafic dont la partie carto est géoréférencée, mais bon tout cela n'est pas le problème) le truc, c'est que cette classe en question à été codée à l'époque de java 1.3 (voir 1.2) et donc elle n'a pas évoluée depuis, donc bien que la recompilation en java 1.5 puis 1.6 à fait un énorme bien (on passe de 7min de chargement à 2min) je pense qu'il doit y avoir un moyen d'optimiser le code :

    Premièrement, le fichier est lu avec çà

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    _currentStream	= new DataInputStream(new FileInputStream(file));
    Existe-t-il aujourd'hui une api plus rapide (en peut comme passer par un StringBuffer) ??

    Autre chose :

    dans cette classe il y a beaucoup de truc dans ce genre :

    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
    private final double readDouble() throws IOException
        {
    	long	l	= 0;
    	long	current;
    	int	i;
    	int	shift	= 0;
     
    	for(i = 0; i < 8; i++)
    	{
    	    current	= _currentStream.readUnsignedByte();
    	    l		+= (current << shift);
    	    shift	+= 8;
    	}
     
    	return Double.longBitsToDouble(l);
        }
    Ou même
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    _currentStream.skipBytes(4);
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    _currentStream.readInt();
    J'espère qu'il est possible de faire en sorte que tout ce code puisse être modifié par une version plus vélosse.


    Merci d'avance.

  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
    Il existe la méthode readDouble de DataInputStream. Cependant, il faut faire attention pour voir si le double a un format différent de celui enregistré.

    Il n'existe par contre pas d'adaptation de la classe DataInputStream pour les java.nio. Mais peut-être qu'en ajoutant un BufferedInputStream entre le DataInputStream et le FileInputStream les performances peuvent être améliorées.

    Le StringBuffer/StringBuilder n'est d'aucune utilité ici.

  3. #3
    Membre averti Avatar de BakaOnigiri
    Inscrit en
    Avril 2002
    Messages
    366
    Détails du profil
    Informations forums :
    Inscription : Avril 2002
    Messages : 366
    Points : 437
    Points
    437
    Par défaut
    Citation Envoyé par dingoth Voir le message
    Le StringBuffer/StringBuilder n'est d'aucune utilité ici.
    Je sais bien, c'était juste un exemple de nouvelles api (ou api oubliées ?) qui optimisent énormément les traitement, tout comme les api java.nio qui sont, il me semble, beaucoup trop ignorées.

    je vais tester le BufferedInputStream

  4. #4
    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
    Si tu donnes un peu plus de code des méthodes que tu souhaites voir optimisées, on pourra sans doute t'aider davantage

  5. #5
    Membre averti Avatar de BakaOnigiri
    Inscrit en
    Avril 2002
    Messages
    366
    Détails du profil
    Informations forums :
    Inscription : Avril 2002
    Messages : 366
    Points : 437
    Points
    437
    Par défaut
    Bon déjà un BufferedInputStream aide beaucoup

    sans :

    >> temps de chargement : 21820 ms
    avec () :

    >> temps de chargement : 880 ms
    Et çà, c'est déjà génial en soi.


    Bon sinon le code qui je sais prend le plus de temps :

    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
    private final void readBody()
        {
    	while(readRecordHeader())
    	{
    	    try
    	    {
    		readRecordContents();
    	    }
    	    catch(Exception e)
    	    {
    		return;
    	    }
    	}
     
    	return;
        }
    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
    private final boolean readRecordHeader()
        {
    	try
    	{
    	    // Record index
    	    _currentStream.readInt();
     
    	    // Length
    	    int	length	= _currentStream.readInt();
     
    	    return (length != 0);
    	}
    	catch(Exception e)
    	{
    	    return false;
    	}
        }
    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
    private final void readRecordContents() throws IOException
        {
    	// Get type for the next shape to read.
    	int	stype	= readInt();
     
    	switch(stype)
    	{
    	    case 0:	// nothing...
    		break;
     
    	    case 1:	// point
    		readPoint();
    		_currentShape++;
     
    		break;
     
    	    case 3:	// arc
    		readPolyline(false);
    		_currentShape++;
     
    		break;
     
    	    case 5:	// polygon
    		readPolyline(true);
    		_currentShape++;
     
    		break;
     
    	    case 8:	// multi points
    		readSimplePolyline();
    		_currentShape++;
     
    		break;
     
    	    default:	// !!!
    		throw new IOException("Unknown record type");
    	}
        }
    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
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    private void readPolyline(boolean filled) throws IOException
        {
    	// skip bounding box.
    	double	xMin	= readDouble();
    	double	yMin	= readDouble();
    	double	xMax	= readDouble();
    	double	yMax	= readDouble();
    	double	x, y;
     
    	// Read number of parts in the current shape.
    	int	nParts	= readInt();
     
    	// Read total number of points in the current shape.
    	int	nPoints	= readInt();
     
    	// Read start index for each part
    	int	parts[]	= new int[nParts];
     
    	for(int i = 0; i < nParts; i++)
    	{
    	    parts[i]	= readInt();
    	}
     
    	// Compute the corresponding number of points for each part
    	int	nums[]	= new int[nParts];
     
    	for(int i = 0; i < nParts; i++)
    	{
    	    if(i != nParts - 1)
    	    {
    		nums[i]	= parts[i + 1] - parts[i];
    	    }
    	    else
    	    {
    		nums[i]	= nPoints - parts[i];
    	    }
    	}
     
    	// Array for points to read
    	double	xi[]		= null;
    	double	yi[]		= null;
    	int	currentPart	= 0;
    	int	p		= 0;
     
    	// Color col = new Color((float)Math.random(), (float)Math.random(), (float)Math.random());
    	// Read until the total number of points has been read.
    	for(int i = 0; i < nPoints; )
    	{
    	    // Starting points of a part
    	    if(i == parts[currentPart])
    	    {
    		// Number of points for that part
    		int	np	= nums[currentPart];
     
    		if(np <= 0)
    		{
    		    continue;
    		}
     
    		// Read all points
    		xi	= new double[np];
    		yi	= new double[np];
     
    		for(int j = 0; j < np; j++)
    		{
    		    x	= readDouble();
    		    y	= readDouble();
     
    		    if(j == 0)
    		    {
    			xMin	= x;
    			yMin	= y;
    			xMax	= x;
    			yMax	= y;
    		    }
    		    else
    		    {
    			xMin	= Math.min(x, xMin);
    			yMin	= Math.min(y, yMin);
    			xMax	= Math.max(x, xMax);
    			yMax	= Math.max(y, yMax);
    		    }
     
    		    if(_projection != null)
    		    {
    			if((x > 180) || (x < -180))
    			{
    			    xi[j]	= x;
    			    yi[j]	= y;
    			}
    			else
    			{
    			    _projection.project(xToRadians(x), yToRadians(y), _projected);
    			    xi[j]	= _projected.x;
    			    yi[j]	= _projected.y;
    			}
    		    }
    		    else
    		    {
    			xi[j]	= x;
    			yi[j]	= y;
    		    }
     
    		    i++;	// increment the number of points we've read
    		}
     
    		// Create Polyline or Polylgon
    		if(filled)
    		{
    		    GISPolyline	poly	= new GISPolyline.Double(xi, yi, LxGisPolyline.FILLED_POLY);
     
    		    _data.addObject(poly, _currentLayerIndex, 0);
     
    		    // poly.setStatus(col);
    		    poly.setID(new Integer(_currentShape));
    		    _shapes.addElement(poly);
     
    		    if(_isLabellized)
    		    {
    			poly.setType(GISPolyline.HIDDEN_POLY);
    		    }
    		}
    		else
    		{
    		    GISPolyline	poly	= new GISPolyline.Double(xi, yi, GISPolyline.OPENED_POLY);
     
    		    _data.addObject(poly, _currentLayerIndex, 0);
    		    _shapes.addElement(poly);
    		    poly.setID(new Integer(_currentShape));
     
    		    if(_isLabellized)
    		    {
    			poly.setType(GISPolyline.HIDDEN_POLY);
    		    }
    		}
     
    		// Next part
    		currentPart++;
    	    }
    	}
        }

    Et alors là, moi pour optimiser tout çà .... je suis pas super doué, surtout que là je pense que c'est plus de l'algo maintenant.


    En tout cas merci beaucoup, çà à déjà énormément changé les performances au chargement de cette application.

  6. #6
    Membre averti Avatar de BakaOnigiri
    Inscrit en
    Avril 2002
    Messages
    366
    Détails du profil
    Informations forums :
    Inscription : Avril 2002
    Messages : 366
    Points : 437
    Points
    437
    Par défaut
    Bon je viens de faire un test avec la carto complète (le test plus haut ne chargeait q'un seul fichier, on en a 10 en tout)

    Sans optimisation :

    >> temps de chargement : 58401 ms
    Avec l'optimisation :

    >> temps de chargement : 2330 ms

    C'est tout simplement merveilleux !!!!!

    Merci pour tout dingoth et merci developpez.com !

  7. #7
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,


    Quelques détails quand au BufferedOutputStream....

    Je n'ai fais que survoler ton code mais j'y vois un grand nombre de readXXX() donc c'est normal que cela prenait beaucoup de temps : chaque appel à une méthode readXXX() génèrerait un accès disque et donc des attentes dû aux entrées/sorties...


    Le BufferedOutputStream englobe en fait le flux, et lorsque tu lis un éléments il lit en fait une grosse partie du fichier dans un buffer en mémoire, et tous les accès suivant sont fait sur ce buffer. Donc il diminue d'autant les accès au disque et donc les performances.

    Pour info par défaut il utilise un buffer de 8192 bytes, mais selon la taille moyenne de tes fichiers ce serait peut-être mieux d'augmenter cette valeur en utilisant le second constructeur BufferedOutputStream(OutputStream, int)...


    a++

  8. #8
    Membre averti Avatar de BakaOnigiri
    Inscrit en
    Avril 2002
    Messages
    366
    Détails du profil
    Informations forums :
    Inscription : Avril 2002
    Messages : 366
    Points : 437
    Points
    437
    Par défaut
    A oui, dimensionner le BufferedInputStream, bonne idée, la plupart de mes fichiers font plus de 10Mo en rarement plus de 20Mo, j'esseyerais demain.


    Merci.

  9. #9
    Membre chevronné
    Profil pro
    Fabrication GED
    Inscrit en
    Octobre 2005
    Messages
    1 405
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Fabrication GED

    Informations forums :
    Inscription : Octobre 2005
    Messages : 1 405
    Points : 1 958
    Points
    1 958
    Par défaut
    Je te confirme qu'augmenter la taille des bufferxxputstream améliore grandement les performances.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. stack smashing detected lors d'une lecture de fichier
    Par Dave62 dans le forum Débuter
    Réponses: 5
    Dernier message: 06/11/2009, 13h50
  2. creer un XMLNode sans une lecture de fichier XML
    Par bruman dans le forum Flash
    Réponses: 1
    Dernier message: 06/01/2009, 13h37
  3. Une lecture de fichier midi qui consomme trop de mémoire
    Par padodanle51 dans le forum Général Java
    Réponses: 6
    Dernier message: 12/04/2008, 11h52
  4. Réponses: 11
    Dernier message: 27/04/2006, 08h56
  5. [VB.NET] Une lecture de fichier difficile...
    Par Abalalojik dans le forum ASP.NET
    Réponses: 29
    Dernier message: 07/01/2005, 14h27

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