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 :

Generer une liste de fichier/dossiers à partir d'un dossier


Sujet :

Langage Perl

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Août 2005
    Messages
    346
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2005
    Messages : 346
    Par défaut Generer une liste de fichier/dossiers à partir d'un dossier
    Bonjour,

    j'ai recherché "glob" sur ce forum pour trouver ce qui m'interesse (et ça y répond bien ) mais j'aurai besoin de vos conseils éclairés pour ma situation plus précise:

    j'utilise actuellement une fonction bricolé avec un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    `dir /b /a:-D "$rep"`; # non recursif
    `dir /b /s /a:-D "$rep"`; # Recursif
    dont je ne suis pas très fier qui permet de:
    - renvoyer la liste des dossiers dans un répertoire
    - renvoyer la liste des fichiers dans un répertoire
    - idem récursivement
    La liste renvoyée contient dans les 4 cas des chemins absolus.

    Je voudrai faire une fonction portable (unix/dos), et surtout qui soit efficace au niveau vitesse/consommation mémoire. Car je devrai utiliser cette fonction pour (entre autres) lister récursivement le contenu d'un dossier qui contiendra sur plusieurs niveaux plusieurs dizaines de milliers de fichiers/dossiers.

    J'ai trouvé sur le forum du code File:Find pour la recherche récursive... que pensez-vous de son efficacité ? glob pour le non récursif (mais pas de distinction fichiers/dossier) qui, parait-il, bouffe beaucoup de ressources...

    Merci d'avance pour vos conseils éclairés

    Bon week end.

  2. #2
    Expert confirmé
    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
    Par défaut
    File::Find est très efficace, meilleur que find dans certains cas. glob() n'est pas particulièrement efficace, et la façon standard de lister un répertoire est d'utiliser opendir()/readdir()/closedir(). En particulier readdir() en contexte scalaire ne renvoie les noms de fichier qu'un à la fois ce qui évite de se trainer des listes énormes.

    La question principale c'est à quoi va te servir ce listing de fichier ? As-tu besoin d'effectuer une opération sur chaque ? As-tu juste besoin de les afficher ? (si tu as besoin de les afficher, ais bien conscience que le facteur limitant sera plutôt la vitesse de ton terminal...) De les écrire dans un fichier ?
    Est-il important que les chemins soient absolus ? (File::Spec->rel2abs() est complètement portable, c'est ce que tu devrais utiliser, exemple sur ce script, en conjonction avec File::Find, utilises le plutôt sur les paramètres de find(), ça sera plus efficace que de le mettre dans le callback)

    --
    Jedaï

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Août 2005
    Messages
    346
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2005
    Messages : 346
    Par défaut
    Bonjour Jedai, merci pour ta réponse rapide.

    Alors - actuellement - j'utilise cette liste en tant que liste (donc je n'utilise pas les avantages de certaines fonctions avec le contexte scalaire). Je n'ai pas toujours une opération à effectuer sur chaque élément... en fait, tout dépend du script car j'utiliserai cette fonction dans un script commun appelé par d'autres.

    Dans le cas le plus contraignant, le script appelle cette fonction qui renvoit une liste enorme, et ceci est remarquablement long... Cette liste est ensuite travaillée par plusieurs boucles qui organisent la structure des fichiers dans un hachage. En gros, ça fait presque le travail qui devrait être fait par une base de données (simple du genre les fichiers .dir et .pag de DB Perl) mais je devais m'affranchir de la dépendance à des fichiers autres que les fichiers de données (ceux que je liste), de sorte que placer ou supprimer des dossiers dans le systeme ne perturbe en rien le script.
    Au final, je pense à continuer mais en ajoutant un index dans une db perl, qui sera mis à jour de temps en temps pour accélerer les choses.

    Au départ la fonction de listage n'était pas vraiment pensée pour ça et je dois un peu tout revoir. Mais je veux conserver une certaine compatibilité avec le comportement actuel car je ne pourrai pas mettre à jour tous les scripts qui l'utilisent rapidement.
    D'ailleurs, meme l'utilisation de db perl pour construire mon hachage (qui contient la liste retravaillée) me parait relativement longue vu le nombre d'éléments.

    Bon... je sais que ça peut ne pas paraître très clair,mais j'espere que ça précise assez ce dont j'ai besoin...

    Pour conclure, j'utiliserai File::Find pour la liste des fichiers/dossiers récursif, mais y a t il un moyen de l'utiliser non récursivement (juste le contenu du dossier en argument?).

    Pourquoi utiliser File::Spec->rel2abs() alors que File:Find:name renvoit deja un chemin absolu?

  4. #4
    Expert confirmé
    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
    Par défaut
    Citation Envoyé par Splug
    Dans le cas le plus contraignant, le script appelle cette fonction qui renvoit une liste enorme, et ceci est remarquablement long...
    Je pense qu'utiliser les outils que je t'ai indiqué devrait aider pour cette partie.

    Bon... je sais que ça peut ne pas paraître très clair,mais j'espere que ça précise assez ce dont j'ai besoin...
    En fait tu as l'air d'avoir besoin de quelque chose d'assez polyvalent, donc utilisant un callback comme File::Find... Ca t'éviterais de toujours renvoyer une grosse liste, tu peux passer un callback qui construit directement le hash (tu comprends comment faire ça ?). Et tu peux toujours faire une fonction de listage compatible avec l'ancienne avec :
    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
    use File::Find;
    use File::Spec;
     
    sub list {
      my ($path, $recursive) = @_;
      $path = File::Spec->rel2abs( $path );
     
      my @files;
     
      if( $recursive ) {
        find( { wanted => sub { push @files, $File::Find::name },
          no_chdir => 1 }, $path );
      } else {
        opendir my($dir), $path;
        @files = map { File::Spec->catfile( $path, $_ ) } (grep m/^\.\.?$/, readdir $dir);
        closedir $dir;
      }
      return @files;
    }
    (NB : Tu prétend que ta fonction `dir /b /a:-D "$rep"` renvoie les chemins absolus mais chez moi ce n'est pas le cas, j'ai tout de même fait ma fonction de façon qu'elle respecte cette contrainte)

    Pour conclure, j'utiliserai File::Find pour la liste des fichiers/dossiers récursif, mais y a t il un moyen de l'utiliser non récursivement (juste le contenu du dossier en argument?).
    Non, mais ce n'est pas nécessaire, la série des fonctions *dir() marche très bien.

    Pourquoi utiliser File::Spec->rel2abs() alors que File:Find:name renvoit deja un chemin absolu?
    Ce n'est pas le cas, teste toi-même :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    perl -MFile::Find -e "find( sub { print $File::Find::name, qq(\n) }, '.')"
    --
    Jedaï

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Août 2005
    Messages
    346
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Août 2005
    Messages : 346
    Par défaut
    Super, c'est presque un chat ce forum

    Merci bcp pour tes conseils, je pense que j'ai tout ce qu'il me faut, je reviendrai si j'ai d'autres questions/problemes car je ne pourrai pas le tester dans l'immédiat.

    (NB : Tu prétend que ta fonction `dir /b /a:-D "$rep"` renvoie les chemins absolus mais chez moi ce n'est pas le cas, j'ai tout de même fait ma fonction de façon qu'elle respecte cette contrainte)
    En effet, je n'ai mis qu'un extrait de ma fonction pour dire à quel point c'était du bricolage mais la suite ajoutait le dossier passé en argument en préfixe.

    Citation:
    Pourquoi utiliser File::Spec->rel2abs() alors que File:Find:name renvoit deja un chemin absolu?

    Ce n'est pas le cas, teste toi-même :
    Pourtant ceci (récupéré sur ce forum):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    use File::Find;
    use strict;
    my $dossier = "d:/blabla";
    my(@files, @dirs);
    find({wanted => \&push_filename, no_chdir => 0 }, $dossier );
    print "Fichiers: $#files\nDossiers: $#dirs\n$files[0]\n";
     
    sub push_filename {
      push @files, $File::Find::name if -f $_;
      push @dirs, $File::Find::name if -d $_;
    }
    m'affiche un chemin absolu...

  6. #6
    Expert confirmé
    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
    Par défaut
    Citation Envoyé par Splug
    En effet, je n'ai mis qu'un extrait de ma fonction pour dire à quel point c'était du bricolage mais la suite ajoutait le dossier passé en argument en préfixe.
    D'accord, je comprend mieux.

    Citation Envoyé par Splug
    Pourtant ceci (récupéré sur ce forum):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    use File::Find;
    use strict;
    my $dossier = "d:/blabla";
    my(@files, @dirs);
    find({wanted => \&push_filename, no_chdir => 0 }, $dossier );
    print "Fichiers: $#files\nDossiers: $#dirs\n$files[0]\n";
     
    sub push_filename {
      push @files, $File::Find::name if -f $_;
      push @dirs, $File::Find::name if -d $_;
    }
    m'affiche un chemin absolu...
    Oui, mais ce code (de moi d'ailleurs) ne retourne le chemin absolu que parce qu'on lui a passé un chemin absolu ("d:/blabla") en paramètre. Tu remarqueras d'ailleurs que ma fonction utilise cette propriété : je n'utilise pas rel2abs() à l'intérieur du callback de find() mais bien sur le paramètre de find(), ainsi il n'est appelé qu'une seule fois (au lieu d'autant de fois qu'il y a de fichiers).

    Dans l'exemple que je te demandais de tester :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    perl -MFile::Find -e "find( sub { print $File::Find::name, qq(\n) }, '.')"
    le chemin passé en paramètre (".") est relatif et les $File::Find::name le sont aussi en conséquence.

    --
    Jedaï

Discussions similaires

  1. Réponses: 1
    Dernier message: 28/01/2015, 16h05
  2. Réponses: 1
    Dernier message: 06/02/2009, 18h58
  3. Réponses: 2
    Dernier message: 01/05/2008, 14h36
  4. Réponses: 7
    Dernier message: 02/07/2007, 15h37
  5. Créer une variable d'environnement à partir d'une liste de fichier
    Par ddams dans le forum Shell et commandes GNU
    Réponses: 2
    Dernier message: 23/02/2007, 21h03

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