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

Android Discussion :

Concaténer des chaînes de manière efficace


Sujet :

Android

  1. #1
    Membre éprouvé
    Avatar de ChPr
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    2 022
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 78
    Localisation : France, Val d'Oise (Île de France)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 2 022
    Points : 1 049
    Points
    1 049
    Par défaut Concaténer des chaînes de manière efficace
    Bonjour à toutes et à tous,

    Dans une application, je souhaite enregistrer un fichier XML. Pour ce faire, je construit une chaîne composée des différentes informations puis j'enregistre cette chaîne. Le code est le suivant pour la formation de la chaîne :

    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
        for (int j = 0; j < ptsTrk.length; j++)
            strTrk = strTrk+trkGPX(ptsTrk[j].lat, ptsTrk[j].lon, ptsTrk[j].alti, ptsTrk[j].date);
     
        private static String trkGPX(double lat, double lon, double ele, String dt) {
            minmax(lat, lon);
            String str = "<trkpt lat=\""+String.format(Locale.US, "%.9f", lat)+"\" lon=\""+String.format(Locale.US, "%.9f", lon)+"\">"
                    +"<ele>"+String.format(Locale.US, "%.6f", ele)+"</ele>"
                    +"<time>"+dt+"</time>"
                    +"</trkpt>";
            return str;
        }
        private static void minmax(double lat, double lon) {
            if (lat < minLat) minLat = lat; else    if (lat > maxLat) maxLat = lat;
            if (lon < minLon) minLon = lon; else    if (lon > maxLon) maxLon = lon;
        }
    Sur mon Galaxy S2, pour 640 points (j de 0 à 639) cette procédure me prend 6 secondes ! Mais ce qui m'a étonné le plus est que ce qui consomme le plus de temps (4 secondes sur les 6) est le fait d'allonger la chaîne, c'est-à-dire de faire :

    Y a-t-il une méthode plus efficace ?

    Par ailleurs, l'instruction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    String.format(Locale.US, "%.9f", lat)
    prend donc à elle seule prés de 2/(640 x 3) soit environ 1 milliseconde, ce qui me semble énorme. Y a-t-il une méthode de conversion plus rapide ?

    Merci de votre aide.

    Pierre

  2. #2
    Modérateur
    Avatar de Hizin
    Homme Profil pro
    Développeur mobile
    Inscrit en
    Février 2010
    Messages
    2 180
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur mobile

    Informations forums :
    Inscription : Février 2010
    Messages : 2 180
    Points : 5 072
    Points
    5 072
    Par défaut
    Pour de la concaténation, utilise plutôt un StringBuilder (documentation), ou un StringBuffer si la synchronisation est important pour toi.

    As-tu réellement besoin d'un XML par contre ? Des POJO que tu pourrais sérialiser ne pourrait correspondre à ton besoin ? Ou du JSON, moins verbeux ? Ou encore une BDD SQLite ?
    C'est Android, PAS Androïd, ou Androïde didiou !
    Le premier est un OS, le second est la mauvaise orthographe du troisième, un mot français désignant un robot à forme humaine.

    Membre du comité contre la phrase "ça marche PAS" en titre et/ou explication de problème.

    N'oubliez pas de consulter les FAQ Android et les cours et tutoriels Android

  3. #3
    Membre éprouvé
    Avatar de ChPr
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    2 022
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 78
    Localisation : France, Val d'Oise (Île de France)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 2 022
    Points : 1 049
    Points
    1 049
    Par défaut
    Merci Hizin, je vais voir la doc du StringBuilder.

    Le XML n'est pas un choix personnel, c'est le format des fichiers d'échange de données cartographiques ".gpx".

    Cordialement.

    Pierre

  4. #4
    Modérateur
    Avatar de Hizin
    Homme Profil pro
    Développeur mobile
    Inscrit en
    Février 2010
    Messages
    2 180
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur mobile

    Informations forums :
    Inscription : Février 2010
    Messages : 2 180
    Points : 5 072
    Points
    5 072
    Par défaut
    Ok.

    Dans ce cas, il faudrait peut-être t'orienter vers des bibliothèques de gestion XML. Je pense à XPath, qui est embarquée avec Android depuis la 2.2. Elle est réputée lente par contre, mais te permettra de construire les XML avec plus de flexibilité.
    C'est Android, PAS Androïd, ou Androïde didiou !
    Le premier est un OS, le second est la mauvaise orthographe du troisième, un mot français désignant un robot à forme humaine.

    Membre du comité contre la phrase "ça marche PAS" en titre et/ou explication de problème.

    N'oubliez pas de consulter les FAQ Android et les cours et tutoriels Android

  5. #5
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    757
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 757
    Points : 968
    Points
    968
    Par défaut
    Citation Envoyé par ChPr Voir le message
    Par ailleurs, l'instruction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    String.format(Locale.US, "%.9f", lat)
    prend donc à elle seule prés de 2/(640 x 3) soit environ 1 milliseconde, ce qui me semble énorme. Y a-t-il une méthode de conversion plus rapide ?
    Oui c'est possible d'améliorer, même si je ne saurais te dire le temps que tu va gagner.
    La méthode format() est définie ainsi : public static String format (String format, Object... args)
    Cela veut dire que tu peux passer un nombre x d'arguments (x >= 0) qui remplaceront le paramètre args.
    Du coup, ta méthode peut se résumer à :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    String str = "<trkpt lat=\"%.9f\" lon=\"%.9f\" ....";
    return String.format(Locale.US, str, lat, lon, ele);
    Tu évite ainsi plusieurs appels à la méthode format et tu évites de concaténer les chaines de caractères.

  6. #6
    Membre éprouvé
    Avatar de ChPr
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    2 022
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 78
    Localisation : France, Val d'Oise (Île de France)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 2 022
    Points : 1 049
    Points
    1 049
    Par défaut
    Merci simon de me rappeler cela. J'ai tout mis dans un seul String.format à chaque fois que possible, exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    		String str = String.format(Locale.US, "<wpt lat=\"%.9f\" lon=\"%.9f\"><ele>%.6f</ele><name>%s</name><cmt></cmt><desc></desc><sym>%d</sym></wpt>", lat, lon, ele, nom, symb);
    Ca semble aller plus vite, mais ce n'est pas évident.

    Hizin : je n'ai pas utilisé de StringBuilder, mais un ArrayList car, autre détail embêtant, je dois compléter la deuxième ligne de mon fichier avec des valeurs que je ne connais qu'après avoir exploré toutes les valeurs du fichier (les min et max).

    Avec ces deux mesures combinées, le temps d’exécution a été divisé dans rapport proche de 10 !

    Cordialement.

    Pierre

  7. #7
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    757
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 757
    Points : 968
    Points
    968
    Par défaut
    Je pense tout de même qu'un StringBuilder serait beaucoup plus rapide.
    C'est quoi cette histoire de deuxième ligne ?

    Voilà ce que tu devrais faire :

    Tu te créé un pattern unique : genre {#1} et {#2} à l'endroit où il te faudra remplir ton min et ton max.
    Générer ton StringBuilder avec des .append(...) à chaque itération.
    A la fin des itérations, tu récupère la String correspondant, puis un simple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    String str = stringBuilder.toString;
    str.replace("{#1}",min);
    str.replace("{#2}",max);
    Par ailleurs, le StringBuilder peut être énormément accéléré en lui donnant une taille d'initialisation. Celle ci est proportionnelle à ton nombre de points (ici ptsTrk.length). Ainsi tu peux initialiser ton StringBuilder comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    StringBuilder stringBuilder = new StringBuilder( 200 /*200 caractères par itération*/ * ptsTrk.length);

  8. #8
    Membre éprouvé
    Avatar de ChPr
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    2 022
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 78
    Localisation : France, Val d'Oise (Île de France)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 2 022
    Points : 1 049
    Points
    1 049
    Par défaut
    Dans la deuxième ligne, je dois donner les valeurs min et max que prennent les latitudes et longitudes des différents points que j'enregistre afin de délimiter la zone sans laquelle figureront tous les points.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    str.replace("{#1}",min);
    Dans le code ci-dessus, le nombre de caractères qui compose la valeur min n'est pas une constante, cela peut être par exemple 1.xxxxxxxxx ou -87.xxxxxxxxx (2 caractères de plus). Est-ce que cela ne posera pas de problème dans la structure StringBuilder ? NOTA : je pourrais prévoir de la place pour la chaîne la plus longue, mais alors, l'interpréteur de fichier .xml me signalera une erreur s'il rencontre des espaces bouche-trous.

    Cordialement.

    Pierre

  9. #9
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2011
    Messages
    757
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2011
    Messages : 757
    Points : 968
    Points
    968
    Par défaut
    Non, en fait, le StringBuilder permet de construire une chaine de caractère.
    Il est utile car l'Objet String est immutable (c'est à dire qu'il ne peut pas être modifié) et cela permet d'éviter des allocations trop nombreuses.
    Par ailleurs, l'objet StringBuilder ajuste automatiquement sa taille en fonction de ce que tu lui donne.
    Si tu créé un StringBuilder avec une contenance de 100 caractères par exemple, et que tu lui donne plus de 100 caractères, il va augmenter automatiquement sa taille (il y a peut être une formule derrière ça, mais je n'en sais trop rien).
    Ceci étant dis, le StringBuilder a déjà une contenance par défaut. Mais l'opération d'augmentation de taille est une opération coûteuse. Il faut l'ajuster au mieux dès le départ

  10. #10
    Membre éprouvé
    Avatar de ChPr
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    2 022
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 78
    Localisation : France, Val d'Oise (Île de France)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 2 022
    Points : 1 049
    Points
    1 049
    Par défaut
    Je viens de lire un peu plus en détail la documentation de StringBuilder et celle de la norme GPX. En fait la souplesse des deux devrait me permettre de faire quelque chose de simple etr rapide.

    Merci à vous.

    Pierre

  11. #11
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    En fait si on se penche un peu sur le code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    String toto, tata;
     
    toto = toto + tata;
    Est traduit par le compilateur en:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    String toto, tata;
     
    StringBuilder tmp_toto = new StringBuilder(toto);
    tmp_toto.append(tata);
    toto = tmp_toto.toString();
    Imagine donc cela fait dans une boucle....
    N'oubliez pas de cliquer sur mais aussi sur si un commentaire vous a été utile !
    Et surtout

  12. #12
    Membre éprouvé
    Avatar de ChPr
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    2 022
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 78
    Localisation : France, Val d'Oise (Île de France)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 2 022
    Points : 1 049
    Points
    1 049
    Par défaut
    Effectivement, cette construction itérée relève de la catastrophe.

    Mais comment fait-on pour savoir ce que traduit le compilateur ?

    Bon, finalement, j'ai utilisé" un StringBuilder et j'ai vu que dans la norme .pcx la conversion des "float" en "String" ne nécessitaient pas un nombre de décimales fixe, ce qui m'a permis de remplacer les "String.format("%.9f", mon_float)" en ".append(mon_float)".

    Cet ensemble m'a encore fait gagner du temps. Ma procédure à l'allure suivante :

    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
    	public static void EngrGPX(PTS[] ptsRep, String[] lstTrk) {
    		StringBuilder sB = new StringBuilder();
    		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
    		String str = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
    				+"<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" creator=\"ChP\" version=\"1.1\""
    				+" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
    				+" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">"
    				+"<metadata><time>"+sdf.format(new Date())+"</time>"
    				+"<bounds minlat=\"";
    		int lLgn = str.length(); // Point pour connaître l'endroit où insérer les min et max
    		sB.append(str);
    		sB.append("\"/></metadata>");
     		for (int i = 0; i < ptsRep.length; i++) { //les Waypoints
     			minmax(ptsRep[i].lat, ptsRep[i].lon);
     			sB.append("<wpt lat=\"").append(ptsRep[i].lat).append("\" lon=\"").append(ptsRep[i].lon)
     				.append("\"><ele>").append(ptsRep[i].alti).append("</ele><name>").append(ptsRep[i].nom)
     				.append("</name><cmt></cmt><desc></desc><sym>").append(ptsRep[i].noIcon).append("</sym></wpt>");
     		}
     		sB.append("<trk>");
      	for (int i = 0; i < lstTrk.length; i++) { //Les traces qui sont dans un tableau de fichiers
      		sB.append("<name>").append(lstTrk[i].substring(0, lstTrk[i].length()-4)).append("</name><trkseg>"); // Suppression de l'extension du fichier
      		PTS[] ptsTrk = TRK.tblPtTrek(FCH.dirVal, lstTrk[i]);
      		for (int j = 0; j < ptsTrk.length; j++) { // Les points d'une trace
       			minmax(ptsTrk[j].lat, ptsTrk[j].lon);
       			sB.append("<trkpt lat=\"").append(ptsTrk[j].lat).append("\" lon=\"").append(ptsTrk[j].lon)
       				.append("\"><ele>").append(ptsTrk[j].alti).append("</ele>").append("</trkpt>");
      		}
      		sB.append("</trkseg>");
      	}
      	sB.append("</trk></gpx>");
      	sB.insert(lLgn, String.format(Locale.US, "%.6f", minLat)+"\" minlon=\""+String.format(Locale.US, "%.6f", minLon) // insertion des min et max
    				+"\" maxlat=\""+String.format(Locale.US, "%.6f", maxLat)+"\" maxlon=\""+String.format(Locale.US, "%.6f", maxLon));
    		BufferedWriter fchGPX = FCH.ouvreEnrg("Xport", ".gpx");
      	try {
     			fchGPX.write(sB.toString()); // Enregistrement de la chaîne
      	}
      	catch (IOException e) {
      		e.printStackTrace();
      	} 
    		FCH.clotEnrg(fchGPX);
    	}
    Cordialement.

    Pierre

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

Discussions similaires

  1. Concaténer des chaînes et des contenus de fichiers
    Par gvdmoort dans le forum Shell et commandes GNU
    Réponses: 3
    Dernier message: 01/08/2013, 17h08
  2. Concaténer des chaînes
    Par Mr_Chut dans le forum Télécharger
    Réponses: 0
    Dernier message: 01/12/2010, 10h31
  3. Réponses: 10
    Dernier message: 23/09/2008, 13h15
  4. Réponses: 20
    Dernier message: 05/01/2008, 11h52
  5. Comment concaténer des chaînes issues d'un fichier ini ?
    Par Neit_Sabes dans le forum Framework .NET
    Réponses: 10
    Dernier message: 27/09/2006, 09h28

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