Gestion des chemins de fichiers et de répertoires

Pour une plongée approfondie dans les opérations pratiques du système de fichiers, consultez notre article de blog : 10 Opérations Essentielles du Système de Fichiers que Tout Développeur Devrait Connaître.

Il existe deux modules principaux en Python qui traitent de la manipulation des chemins. L’un est le module os.path et l’autre est le module pathlib.

Pathlib vs Module OS

pathlib offre beaucoup plus de fonctionnalités que celles énumérées ci-dessus, comme obtenir le nom du fichier, obtenir l'extension du fichier, lire/écrire un fichier sans l'ouvrir manuellement, etc. Consultez la documentation officielle si vous souhaitez en savoir plus.

Chemins Linux et Windows

Sous Windows, les chemins sont écrits en utilisant des barres obliques inverses (\) comme séparateur entre les noms de dossiers. Sur les systèmes d’exploitation basés sur Unix tels que macOS, Linux et BSD, la barre oblique avant (/) est utilisée comme séparateur de chemin. Joindre des chemins peut être un casse-tête si votre code doit fonctionner sur différentes plateformes.

Heureusement, le module pathlib de Python fournit un moyen facile de gérer cela.

Utilisation de pathlib sur *nix :

# pathlib.Path: gestion de chemins multiplateformes
from pathlib import Path

print(Path('usr').joinpath('bin').joinpath('spam'))  # Joindre des composants de chemin
usr/bin/spam

pathlib fournit également un raccourci pour joinpath en utilisant l’opérateur / :

# Opérateur Path (/): moyen pratique de joindre des chemins (multiplateforme)
from pathlib import Path

print(Path('usr') / 'bin' / 'spam')  # Utiliser l'opérateur / au lieu de joinpath()
usr/bin/spam

Remarquez que le séparateur de chemin est différent entre Windows et les systèmes d’exploitation basés sur Unix, c’est pourquoi vous voulez utiliser pathlib au lieu d’ajouter des chaînes de caractères ensemble pour joindre des chemins.

Quiz

Connectez-vous pour répondre à ce quiz et suivre votre progression d'apprentissage

Quelle est la bonne façon de joindre des chemins en utilisant pathlib en Python ?
A. Path('usr') + 'bin' + 'spam'
B. Path('usr') / 'bin' / 'spam'
C. Path('usr').join('bin').join('spam')
D. Path('usr/bin/spam')

Joindre des chemins est utile si vous avez besoin de créer différents chemins de fichiers sous le même répertoire.

Utilisation de pathlib sur *nix :

# Path.home(): obtenir le répertoire personnel de l'utilisateur, combiner avec des noms de fichiers
my_files = ['accounts.txt', 'details.csv', 'invite.docx']
home = Path.home()  # Obtenir le chemin du répertoire personnel
for filename in my_files:
    print(home / filename)  # Combiner le chemin personnel avec chaque nom de fichier
/home/labex/project/accounts.txt
/home/labex/project/details.csv
/home/labex/project/invite.docx

Expansion du répertoire personnel de l’utilisateur

Utilisation de os.path.expanduser() pour développer ~ en répertoire personnel de l’utilisateur :

import os.path

# Développer ~ en répertoire personnel de l'utilisateur
print(os.path.expanduser('~'))
/home/labex/project
# Développer ~/Documents en chemin complet
print(os.path.expanduser('~/Documents'))
/home/labex/project/Documents
# Fonctionne avec les chemins contenant ~
print(os.path.expanduser('~/myfile.txt'))
/home/labex/project/myfile.txt

Le répertoire de travail actuel

Vous pouvez obtenir le répertoire de travail actuel en utilisant pathlib :

# Path.cwd(): obtenir le répertoire de travail actuel
from pathlib import Path

print(Path.cwd())  # Retourne le répertoire de travail actuel sous forme d'objet Path
/home/labex/project

Création de nouveaux dossiers

Utilisation de pathlib sur *nix :

from pathlib import Path
cwd = Path.cwd()
(cwd / 'delicious' / 'walnut' / 'waffles').mkdir()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.6/pathlib.py", line 1226, in mkdir
    self._accessor.mkdir(self, mode)
  File "/usr/lib/python3.6/pathlib.py", line 387, in wrapped
    return strfunc(str(pathobj), *args)
FileNotFoundError: [Errno 2] No such file or directory: '/home/labex/project/delicious/walnut/waffles'

Oh non, nous avons une erreur gênante ! La raison est que le répertoire ‘delicious’ n’existe pas, nous ne pouvons donc pas créer les répertoires ‘walnut’ et ‘waffles’ en dessous. Pour corriger cela, faites :

# mkdir(parents=True): créer le répertoire et tous les répertoires parents si nécessaire
from pathlib import Path
cwd = Path.cwd()
(cwd / 'delicious' / 'walnut' / 'waffles').mkdir(parents=True)  # Créer des répertoires imbriqués

Et tout va bien :)

Chemins absolus vs relatifs

Il existe deux façons de spécifier un chemin de fichier.

  • Un chemin absolu, qui commence toujours par le dossier racine
  • Un chemin relatif, qui est relatif au répertoire de travail actuel du programme

Il existe également les dossiers point (.) et double point (..). Ce ne sont pas de vrais dossiers, mais des noms spéciaux qui peuvent être utilisés dans un chemin. Un seul point (“dot”) pour un nom de dossier est un raccourci pour “ce répertoire”. Deux points (“dot-dot”) signifient “le dossier parent”.

Gestion des chemins absolus

Pour voir si un chemin est un chemin absolu en utilisant pathlib :

from pathlib import Path
Path('/').is_absolute()
True
Path('..').is_absolute()
False
Quiz

Connectez-vous pour répondre à ce quiz et suivre votre progression d'apprentissage

Que retourne Path('/').is_absolute() ?
A. True
B. False
C. None
D. '/'

Vous pouvez extraire un chemin absolu avec pathlib :

from pathlib import Path
print(Path.cwd())
/home/labex/project
print(Path('..').resolve())
/home

Gestion des chemins relatifs

Vous pouvez obtenir un chemin relatif à partir d’un chemin de départ vers un autre chemin en utilisant pathlib :

from pathlib import Path
print(Path('/etc/passwd').relative_to('/'))
etc/passwd

Validité du chemin et du fichier

Vérification de l’existence d’un fichier/répertoire

Utilisation de pathlib sur *nix :

from pathlib import Path

Path('.').exists()
True
Path('setup.py').exists()
True
Path('/etc').exists()
True
Path('nonexistentfile').exists()
False

Vérification si un chemin est un fichier

Utilisation de pathlib sur *nix :

from pathlib import Path

Path('setup.py').is_file()
True
Path('/home').is_file()
False
Path('nonexistentfile').is_file()
False
Quiz

Connectez-vous pour répondre à ce quiz et suivre votre progression d'apprentissage

Que retournera Path('setup.py').is_file() si setup.py existe ?
A. 'setup.py'
B. False
C. True
D. None

Vérification si un chemin est un répertoire

Utilisation de pathlib sur *nix :

from pathlib import Path

Path('/').is_dir()
True
Path('setup.py').is_dir()
False
Path('/spam').is_dir()
False

Obtention de la taille d’un fichier en octets

Utilisation de pathlib sur *nix :

from pathlib import Path

stat = Path('/bin/python3.6').stat()
print(stat) # stat contient également d'autres informations sur le fichier
os.stat_result(st_mode=33261, st_ino=141087, st_dev=2051, st_nlink=2, st_uid=0,
--snip--
st_gid=0, st_size=10024, st_atime=1517725562, st_mtime=1515119809, st_ctime=1517261276)
print(stat.st_size) # taille en octets
10024

Listage des répertoires

Listage du contenu d’un répertoire en utilisant pathlib sur *nix :

from pathlib import Path

for f in Path('/usr/bin').iterdir():
    print(f)
...
/usr/bin/tiff2rgba
/usr/bin/iconv
/usr/bin/ldd
/usr/bin/cache_restore
/usr/bin/udiskie
/usr/bin/unix2dos
/usr/bin/t1reencode
/usr/bin/epstopdf
/usr/bin/idle3
...

Tailles de fichiers de répertoire

ATTENTION

Les répertoires eux-mêmes ont également une taille ! Vous voudrez donc vérifier si un chemin est un fichier ou un répertoire en utilisant les méthodes discutées dans la section précédente.

Utilisation de pathlib sur *nix :

from pathlib import Path

total_size = 0
for sub_path in Path('/usr/bin').iterdir():
    total_size += sub_path.stat().st_size

print(total_size)
1903178911

Copie de fichiers et de dossiers

Le module shutil fournit des fonctions pour copier des fichiers, ainsi que des dossiers entiers.

import shutil

shutil.copy('/tmp/spam.txt', '/tmp/delicious')
/tmp/delicious/spam.txt
shutil.copy('/tmp/eggs.txt', '/tmp/delicious/eggs2.txt')
/tmp/delicious/eggs2.txt
Quiz

Connectez-vous pour répondre à ce quiz et suivre votre progression d'apprentissage

Quelle fonction devez-vous utiliser pour copier une arborescence de répertoires entière, y compris tous les sous-répertoires et fichiers ?
A. shutil.copy()
B. Path.copy()
C. os.copy()
D. shutil.copytree()

Alors que shutil.copy() copiera un seul fichier, shutil.copytree() copiera un dossier entier et tous les dossiers et fichiers qu’il contient :

import shutil

shutil.copytree('/tmp/bacon', '/tmp/bacon_backup')
/tmp/bacon_backup

Déplacement et renommage

import shutil

shutil.move('/tmp/bacon.txt', '/tmp/eggs')
/tmp/eggs/bacon.txt

Le chemin de destination peut également spécifier un nom de fichier. Dans l’exemple suivant, le fichier source est déplacé et renommé :

shutil.move('/tmp/bacon.txt', '/tmp/eggs/new_bacon.txt')
/tmp/eggs/new_bacon.txt

S’il n’y a pas de dossier eggs, alors move() renommera bacon.txt en un fichier nommé eggs :

shutil.move('/tmp/bacon.txt', '/tmp/eggs')
/tmp/eggs

Suppression de fichiers et de dossiers

  • Appeler Path.unlink() supprimera le fichier au chemin spécifié.
  • Appeler Path.rmdir() supprimera le dossier au chemin spécifié. Ce dossier doit être vide de tout fichier ou dossier.
  • Appeler shutil.rmtree(path) supprimera le dossier au chemin spécifié, et tous les fichiers et dossiers qu’il contient seront également supprimés.
Quiz

Connectez-vous pour répondre à ce quiz et suivre votre progression d'apprentissage

Quelle méthode peut supprimer un répertoire non vide et tout son contenu ?
A. Path.rmdir()
B. shutil.rmtree()
C. Path.unlink()
D. os.remove()

Parcours d’une arborescence de répertoires

L’objet Path possède une méthode rglob() pour itérer récursivement sur les fichiers et les répertoires.

from pathlib import Path

p = Path('/tmp/delicious')
for i in p.rglob('*'):
    print(i)
/tmp/delicious/cats
/tmp/delicious/walnut
/tmp/delicious/spam.txt
/tmp/delicious/cats/catnames.txt
/tmp/delicious/cats/zophie.jpg
/tmp/delicious/walnut/waffles
/tmp/delicious/walnut/waffles/butter.txt

Liens pertinents