Dans le cadre d’une macro Gimp Script-Fu de traitement par lot, vous pourriez avoir besoin de parcourir toute une arborescence et pas seulement un répertoire à la recherche de fichier de types précis.
La fonctionfile-glob
permet de le faire mais seulement sur un seul niveau. Voici la fonctionparcours-repertoires
qui permet de combler ce manque.
Pour fonctionner, il vous faut les fonctions suivantes :
Les fonctionsest-un-repertoire?
etest-un-fichier?
sont des fonctions créées pour simplifier l’écriture (la lecture ?) de la fonctionparcours-repertoires
.
La fonctionparcours-repertoires
s’utilise de la façon suivante :
(parcours-repertoires <répertoire> <profondeur max> <liste des extensions recherchées>)
Les paramètres sont les suivants :
La fonctionparcours-repertoires
retourne une liste de tous les fichiers répondant aux critères donnés dans les paramètres. Chaque chaîne contenue dans cette liste est un chemin vers le fichier incluant le répertoire (un chemin absolu si le répertoire fourni est lui-même absolu).
La fonction a été développée sous Linux mais elle devrait également fonctionner sous Windows (mais cela n’a pas été testé !).
Exemple d’appel :
(parcours-repertoires "/home/utilisateur" 16 (list ".png" ".jpg" ".gif"))
; Teste si une valeur se trouve dans une liste
(define (est-dans? valeur liste)
(cond
; Si la liste est nulle, la valeur ne peut pas s’y trouver
((null? liste) #f)
; Si le premier élément de la liste est égale à la valeur on retourne vrai
((equal? valeur (car liste)) #t)
; Sinon on recherche la valeur dans le reste de la liste
(else (est-dans? valeur (cdr liste)))
)
)
; Retourne un nom de fichier sans son extension
(define (sans-extension nom-fichier)
(let loop ((nom nom-fichier))
(cond
; Si le nom est vide, il n’y a pas d’extension, on retourne le nom complet
((string=? nom "") nom-fichier)
; Si le dernier caractère est un séparateur de répertoire
((string=? (substring nom (- (string-length nom) 1) (string-length nom)) DIR-SEPARATOR)
; on retourne le nom complet
nom-fichier
)
; Si le dernier caractère est un point
((char=? (string-ref nom (- (string-length nom) 1)) #\.)
; on retourne le nom en lui enlevant le dernier caractère
(substring nom 0 (- (string-length nom) 1))
)
; Sinon on supprime le dernier caractère du nom et on boucle
(else (loop (substring nom 0 (- (string-length nom) 1))))
)
)
)
; Retourne l’extension d’un nom de fichier
(define (extension nom-fichier)
; Extension=nom de fichier - nom de fichier sans extension
(substring nom-fichier (string-length (sans-extension nom-fichier)))
)
; Vérifie si un chemin est un répertoire
(define (est-un-repertoire? repertoire entree)
(=
(file-type (string-append repertoire DIR-SEPARATOR entree))
FILE-TYPE-DIR
)
)
; Vérifie si un chemin est un fichier standard
(define (est-un-fichier? repertoire entree)
(=
(file-type (string-append repertoire DIR-SEPARATOR entree))
FILE-TYPE-FILE
)
)
; Retourne la liste de tous les fichiers des répertoires et sous-répertoires
(define (parcours-repertoires repertoire niveau extensions)
(let*
(
; Récupère un curseur sur le contenu du répertoire
(stream (dir-open-stream repertoire))
; Récupère la liste des fichiers
(retour
; Boucle sur la liste des fichiers du répertoire
(let loop ((entree (dir-read-entry stream)) (entrees '()))
(cond
; Si on est arrivé en fin de liste, on retourne la liste des
; fichiers trouvés
((or (eof-object? entree) (equal? entree #f)) entrees)
; Si l’entrée est un répertoire et que le niveau le permet,
; on récupère la liste de ses fichiers par récursivité et on
; l’ajoute à la liste en cours
((and (est-un-repertoire? repertoire entree)
(> niveau 1))
(loop
(dir-read-entry stream)
(append
entrees
(parcours-repertoires
(string-append repertoire DIR-SEPARATOR entree)
(- niveau 1)
extensions
)
)
)
)
; Si l’entrée est un fichier et que son extension est dans la liste
; des extensions autorisées, on ajoute l’entrée à la liste en cours
; et on passe à l’entrée suivante
((and (est-un-fichier? repertoire entree)
(est-dans? (extension entree) extensions))
(loop
(dir-read-entry stream)
(cons (string-append repertoire DIR-SEPARATOR entree) entrees)
)
)
; Sinon on passe à l’entrée suivante
(else (loop (dir-read-entry stream) entrees))
)
)
)
)
; Ferme le curseur sur le répertoire
(dir-close-stream stream)
; Retourne la liste des fichiers trouvés
retour
)
)
La fonctionparcours-repertoires
fait appel aux fonctionsdir-open-stream
,dir-read-entry
etdir-close-stream
pour parcourir l’arborescence. Elle ne fait pas appel à la fonctionfile-glob
. En plus du désavantage de ne pouvoir parcourir une arborescence en profondeur, elle n’est pas capable de rechercher plusieurs extensions à la fois.
Concernant l’utilisation de la fonctiondir-read-entry
, j’ai ajouté le test(equal? entree #f)
car il lui arrive de retourner#f
en lieu et place de#<EOF>
. Je ne sais pas pourquoi ! Est-ce une mauvaise utilisation de ma part ? Un bug dansdir-read-entry
? Ou un fonctionnement que je n’aurais pas saisi ? Si quelqu’un a la réponse, je suis preneur !