Skip to article frontmatterSkip to article content
Licence CC BY-NC-ND Thierry Parmentelat

parcours de dossier

en 2024 tous les calculs/parcours sur le contenu du disque, dossiers, fichiers, et métadonnées telles que tailles, dates, etc... se font avec le couteau suisse pathlib

lisez-bien tout le notebook, et surtout les indices, avant de commencer

from pathlib import Path

(et non plus avec os.path et autres glob comme on aurait pu le faire dans le passé)

initialisation

on va partir d’un dossier avec un peu de contenu; c’est pour simuler par exemple un dossier avec des logs

# on nettoie bien tout pour être sûr
!rm -rf pathlib-foo
from files_sortby import init
init()
Wrote file pathlib-foo/logs/file1 - size 11
Wrote file pathlib-foo/logs/dir1/filebxxxxxx - size 12
Wrote file pathlib-foo/logs/dir1/filebbxxxxxx - size 13
Wrote file pathlib-foo/logs/dir1/filebbbxxxxxx - size 14
Wrote file pathlib-foo/logs/file10 - size 10
Wrote file pathlib-foo/logs/dir10/fileaxxxx - size 102
Wrote file pathlib-foo/logs/dir10/fileaaxxxx - size 103
Wrote file pathlib-foo/logs/dir10/fileaaaxxxx - size 104
Wrote file pathlib-foo/logs/file100 - size 9
Wrote file pathlib-foo/logs/dir100/filecxx - size 1002
Wrote file pathlib-foo/logs/dir100/fileccxx - size 1003
Wrote file pathlib-foo/logs/dir100/filecccxx - size 1004

pb1: parcours de dossier

on veut parcourir tout un dossier, c’est-à-dire calculer la liste des fichiers qui se trouvent dans un dossier; et cela récursivement ou pas (en parcourant ou non les sous-dossiers)

on vous demande d’écrire une fonction scan_dir qui prend en paramètres:

et qui renvoie une liste d’objets de type Path, qui correspondent aux fichiers (pas les dossiers) qui se situent en dessous de root/relative

exemples

from files_sortby import scan_dir

for p in scan_dir("pathlib-foo/", relative="logs/dir1", recursive=False):
    print(p)
pathlib-foo/logs/dir1/filebxxxxxx
pathlib-foo/logs/dir1/filebbbxxxxxx
pathlib-foo/logs/dir1/filebbxxxxxx
for p in scan_dir("pathlib-foo/", relative="logs", recursive=True):
    print(p)
pathlib-foo/logs/file1
pathlib-foo/logs/file10
pathlib-foo/logs/file100
pathlib-foo/logs/dir10/fileaxxxx
pathlib-foo/logs/dir10/fileaaxxxx
pathlib-foo/logs/dir10/fileaaaxxxx
pathlib-foo/logs/dir1/filebxxxxxx
pathlib-foo/logs/dir1/filebbbxxxxxx
pathlib-foo/logs/dir1/filebbxxxxxx
pathlib-foo/logs/dir100/filecxx
pathlib-foo/logs/dir100/fileccxx
pathlib-foo/logs/dir100/filecccxx

pb2: idem mais en triant

on veut maintenant pouvoir trier cette information

on veut écrire une fonction sort_dir qui prend les mêmes paramètres, et en plus

exemples

from files_sortby import sort_dir

sort_dir("pathlib-foo", relative="logs", recursive=True, by='size')
[PosixPath('pathlib-foo/logs/file100'), PosixPath('pathlib-foo/logs/file10'), PosixPath('pathlib-foo/logs/file1'), PosixPath('pathlib-foo/logs/dir1/filebxxxxxx'), PosixPath('pathlib-foo/logs/dir1/filebbxxxxxx'), PosixPath('pathlib-foo/logs/dir1/filebbbxxxxxx'), PosixPath('pathlib-foo/logs/dir10/fileaxxxx'), PosixPath('pathlib-foo/logs/dir10/fileaaxxxx'), PosixPath('pathlib-foo/logs/dir10/fileaaaxxxx'), PosixPath('pathlib-foo/logs/dir100/filecxx'), PosixPath('pathlib-foo/logs/dir100/fileccxx'), PosixPath('pathlib-foo/logs/dir100/filecccxx')]
from files_sortby import sort_dir

sort_dir("pathlib-foo", relative="logs", recursive=True, by='namelen')
[PosixPath('pathlib-foo/logs/file1'), PosixPath('pathlib-foo/logs/file10'), PosixPath('pathlib-foo/logs/file100'), PosixPath('pathlib-foo/logs/dir100/filecxx'), PosixPath('pathlib-foo/logs/dir100/fileccxx'), PosixPath('pathlib-foo/logs/dir10/fileaxxxx'), PosixPath('pathlib-foo/logs/dir100/filecccxx'), PosixPath('pathlib-foo/logs/dir10/fileaaxxxx'), PosixPath('pathlib-foo/logs/dir10/fileaaaxxxx'), PosixPath('pathlib-foo/logs/dir1/filebxxxxxx'), PosixPath('pathlib-foo/logs/dir1/filebbxxxxxx'), PosixPath('pathlib-foo/logs/dir1/filebbbxxxxxx')]

Indices

# on utilise ici quelques traits de `pathlib.Path`

from pathlib import Path

# pour construire un Path
root = Path("pathlib-foo")
root
PosixPath('pathlib-foo')
# on peut utiliser l'opérateur `/` pour construire des chemins
# mais ça ne marche pas (évidemment) entre deux chaines
# par contre dès qu'un des deux opérandes est un Path:

path = root / "logs/dir100/filecxx"
path
PosixPath('pathlib-foo/logs/dir100/filecxx')
# ou encore, donne le même résultat

path = root / "logs" / "dir100" / "filecxx"
# pour avoir la taille
path.stat().st_size
1002
# pour chercher les fichiers on peut utiliser la méthode glob
# 2 remarques:
# - ici j'appelle list(), c'est juste pour avoir un affichage correct (essayez de l'enlever...)

logs = root / "logs"

list(logs.glob("*"))
[PosixPath('pathlib-foo/logs/file1'), PosixPath('pathlib-foo/logs/dir10'), PosixPath('pathlib-foo/logs/dir1'), PosixPath('pathlib-foo/logs/file10'), PosixPath('pathlib-foo/logs/file100'), PosixPath('pathlib-foo/logs/dir100')]
# et pour les recherches récursives on fait comme ceci
# le **/ va matcher tous les dossiers en dessous de 'logs'

list(logs.glob("**"))
[PosixPath('pathlib-foo/logs'), PosixPath('pathlib-foo/logs/dir10'), PosixPath('pathlib-foo/logs/dir1'), PosixPath('pathlib-foo/logs/dir100')]
# du coup pour trouver tous les fichiers on fait

list(logs.glob("**/*"))
[PosixPath('pathlib-foo/logs/file1'), PosixPath('pathlib-foo/logs/dir10'), PosixPath('pathlib-foo/logs/dir1'), PosixPath('pathlib-foo/logs/file10'), PosixPath('pathlib-foo/logs/file100'), PosixPath('pathlib-foo/logs/dir100'), PosixPath('pathlib-foo/logs/dir10/fileaxxxx'), PosixPath('pathlib-foo/logs/dir10/fileaaxxxx'), PosixPath('pathlib-foo/logs/dir10/fileaaaxxxx'), PosixPath('pathlib-foo/logs/dir1/filebxxxxxx'), PosixPath('pathlib-foo/logs/dir1/filebbbxxxxxx'), PosixPath('pathlib-foo/logs/dir1/filebbxxxxxx'), PosixPath('pathlib-foo/logs/dir100/filecxx'), PosixPath('pathlib-foo/logs/dir100/fileccxx'), PosixPath('pathlib-foo/logs/dir100/filecccxx')]
# pas utilisé dans cet exercice, mais on peut facilement
# faire des calculs du genre de:

path = root / "logs" / "dir100" / "filecxx"

path.parts
('pathlib-foo', 'logs', 'dir100', 'filecxx')
# ou encore

list(path.parents)
[PosixPath('pathlib-foo/logs/dir100'), PosixPath('pathlib-foo/logs'), PosixPath('pathlib-foo'), PosixPath('.')]
# ou encore

path.absolute()
PosixPath('/home/runner/work/exos-python/exos-python/notebooks/exos/basic/pathlib-foo/logs/dir100/filecxx')
path.relative_to(root)
PosixPath('logs/dir100/filecxx')
# etc etc..

solution

variantes possibles