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

Langage Perl Discussion :

glob & récursivité : étrange problème


Sujet :

Langage Perl

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 66
    Points : 60
    Points
    60
    Par défaut glob & récursivité : étrange problème
    Salut et merci de prendre la peine de lire tout ce qui suit, c'est un peu long mais très simple.
    A la base je voulais créer une version récursive de la fonction glob, pour pouvoir lister des sous-dossiers.

    Voici donc le contexte exact de ma tentative infructueuse de codage récursif :

    - Premièrement, j'ai crée un dossier pour mes tests : "c:/test".
    Dans ce dossier, il y a 3 fichiers texte et 2 sous-dossiers "A" et "B"
    contenant à leur tour resp. deux et un fichiers texte.
    Voici donc le contenu de "c:/test" (2 dossiers, 6 fichiers) :

    - c:/test/A/a_01.txt
    - c:/test/A/a_02.txt
    - c:/test/B/b_01.txt
    - c:/test/x_03.txt
    - c:/test/x_01.txt
    - c:/test/x_02.txt

    Et voici le code de la fonction glob_s dont l'unique paramètre contient
    le nom du dossier dont il faut lister le contenu.
    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
    $count = 0;
    print glob_s("c:/test");
    sub glob_s {
    	#Sans la ligne ci-dessous, il y aurait une boucle infinie !
    	if($count++ > 100){return "";}
    	
    	my($path) = $_[0];
    	my($ret_list) = "\nglob_s CALL #".$count." path = \"".$path."\"\n";	
     	while(glob($path)){
    	 	my($file) = $_;
    	 	if(-f $file){
    		 	$ret_list .= "#".$count."{".$path."}"." found file \"".$file."\"\n";}
    	 	elsif(-d $file){
    		 	$ret_list .= "#".$count."{".$path."}"." found dir \"".$file."\"...\n".glob_s($file."/*");}
     	}
    	return $ret_list;
    }#glob_s
    Et voici le résultat de l'exécution (tronqué, mais l'essentiel tient en quatre lignes) :

    glob_s CALL #1 path = "c:/test"
    #1{c:/test} found dir "c:/test"...

    glob_s CALL #2 path = "c:/test/*"
    #2{c:/test} found dir "c:/test"...

    ... etc ... (jusqu'à #101)

    Il y a un problème flagrant lors du 2ème appel (#2) de glob_s avec la valeur de la variable $path
    qui fait que le texte en vert ne correspond pas au texte en rouge, d'où la boucle infinie.

    Pourquoi diable $path ne garde pas la même valeur à l'intérieur se glob_s ???

  2. #2
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Ta façon de faire pose des problèmes à glob() parce que tu changes de pattern avant d'avoir épuisé le précédent, je te copie la partie pertinente de la documentation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
       A (file)glob evaluates its (embedded) argument only when it is starting
       a new list. All values must be read before it will start over. In list
       context, this isn't important because you automatically get them all
       anyway. However, in scalar context the operator returns the next value
       each time it's called, or "undef" when the list has run out. As with
       filehandle reads, an automatic "defined" is generated when the glob
       occurs in the test part of a "while", because legal glob returns (e.g. a
       file called 0) would otherwise terminate the loop. Again, "undef" is
       returned only once. So if you're expecting a single value from a glob,
       it is much better to say
    En bref, soit tu stockes le retour d'un glob dans un tableau avant d'itérer sur ce tableau, soit tu passes à des outils plus propres et tu utilises le trio opendir(), readdir(), closedir() (meilleure solution point de vue efficacité).

    Cependant, sache que le module File::Find fait exactement ce que tu veux, et il fait partie du CORE.

    --
    Jedaï

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 66
    Points : 60
    Points
    60
    Par défaut
    Merci pour l'info. J'ai effectivement corrigé mon code pour stocker le résultat retourné par glob dans un tableau et tout marche très bien.

    A part ça, d'où sors-tu le texte cité en anglais ? ça m'a l'air d'une excellente documentation, ce que je n'ai pu trouver ni sur Internet, ni avec la fonction "perldoc -f glob".

    Tu mentionnes aussi opendir(), readdir(), closedir() comme étant une "meilleure solution du point de vue efficacité".
    Pourrais-tu développer (un peu) ce que tu entends par là ? S'agit-il juste d'une execution plus rapide ? D'une meilleure robustesse ? Portabilité ?

  4. #4
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Citation Envoyé par Mat_F
    A part ça, d'où sors-tu le texte cité en anglais ? ça m'a l'air d'une excellente documentation, ce que je n'ai pu trouver ni sur Internet, ni avec la fonction "perldoc -f glob".
    Il y a une petite référence à cette documentation dans la doc de glob(), il s'agit d'un bout de perlop.

    Citation Envoyé par Mat_F
    Tu mentionnes aussi opendir(), readdir(), closedir() comme étant une "meilleure solution du point de vue efficacité".
    Pourrais-tu développer (un peu) ce que tu entends par là ? S'agit-il juste d'une execution plus rapide ? D'une meilleure robustesse ? Portabilité ?
    Dans ta solution actuelle tu maintiens un tableau pour chacun des niveaux de profondeur, avec opendir() et readdir() tu peux te contenter de maintenir un handle de répertoire par niveau. De ce fait, sur les arborescences les plus encombrées tu auras peut-être un peu de gain de vitesse, la portabilité sera par ailleurs garantie (avec glob() aussi probablement). Globalement les deux solutions ne sont pas très différentes et si ta fonction marche de façon satisfaisante restes-en là.
    (par contre la meilleure solution reste sans doute File::Find)

    --
    Jedaï

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

Discussions similaires

  1. Réponses: 5
    Dernier message: 13/02/2011, 13h51
  2. étrange problème absence de "lien"
    Par trib_dav dans le forum ActionScript 3
    Réponses: 1
    Dernier message: 24/12/2009, 01h18
  3. Étrange problème de champ introuvable
    Par sfpx dans le forum Bases de données
    Réponses: 1
    Dernier message: 11/02/2009, 13h34
  4. Un bien étrange problème avec mes namespaces
    Par zarbiman dans le forum C#
    Réponses: 5
    Dernier message: 03/03/2007, 18h59
  5. Formulaire au comportement étrange : problème de POST
    Par Chlipouni dans le forum Langage
    Réponses: 6
    Dernier message: 18/07/2006, 11h36

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