Lecture et écriture de fichiers
Les E/S de fichiers franchissent une frontière entre l'état du programme et un système de fichiers externe. Rendez explicites le format, l'encodage, le mode et le comportement en cas d'échec.
Durée de vie des ressources
Utilisez un gestionnaire de contexte afin que le fichier soit fermé même lorsqu'une exception survient :
from pathlib import Path
path = Path("notes.txt")
with path.open("r", encoding="utf-8") as handle:
for line in handle:
process(line.rstrip("\n"))
L'itération sur le fichier diffuse les lignes. read() et readlines() chargent le contenu restant en mémoire et doivent être réservés aux entrées bornées. rstrip("\n") retire la fin de ligne sans supprimer les espaces significatifs comme le ferait un strip() sans argument.
Modes texte et binaire
Le mode texte décode les octets en str ; le mode binaire renvoie des bytes inchangés.
text = path.read_text(encoding="utf-8")
payload = Path("image.bin").read_bytes()
Précisez l'encodage d'un texte durable plutôt que de dépendre des paramètres régionaux de la machine. La conversion des fins de ligne appartient aussi au mode texte ; passez newline= lorsqu'un format exige un contrôle précis.
Les principaux modes sont :
Ajoutez b pour le mode binaire ou + pour combiner lecture et écriture. Considérez w comme une opération destructive.
Formats structurés
Utilisez une bibliothèque qui connaît le format plutôt qu'un découpage manuel de chaînes :
import json
with Path("settings.json").open("r", encoding="utf-8") as handle:
settings = json.load(handle)
Employez csv pour les données délimitées et ouvrez les fichiers CSV avec newline="" comme le recommande sa documentation. L'analyse syntaxique ne valide pas le sens métier ; vérifiez séparément le schéma, les plages et les champs obligatoires.
Échecs et remplacement plus sûr
Ne traitez que les erreurs pour lesquelles le programme possède une stratégie de récupération, telles que FileNotFoundError, PermissionError, les erreurs de décodage ou les données de format invalides. Ne réduisez pas tous les échecs à un résultat vide.
Pour une sortie importante, écrivez un fichier temporaire dans le même répertoire, videz les tampons et fermez-le, puis remplacez la destination. Un renommage dans le même système de fichiers peut éviter aux lecteurs d'observer un fichier partiellement écrit, mais la durabilité après un arrêt brutal peut aussi exiger une synchronisation propre au système. Le remplacement atomique ne coordonne pas plusieurs auteurs concurrents.
Écrire puis relire sans fichier préexistant
Cet exemple utilise un répertoire temporaire isolé, nettoyé à la sortie. Les méthodes des fichiers agissent depuis la position courante du flux, pas depuis le début à chaque appel.
from pathlib import Path
from tempfile import TemporaryDirectory
with TemporaryDirectory() as directory:
path = Path(directory) / "notes.txt"
with path.open("x", encoding="utf-8", newline="\n") as handle:
assert handle.write("café\n\n") == 6
with path.open("r", encoding="utf-8") as handle:
assert handle.readline() == "café\n"
assert handle.readline() == "\n" # ligne vide, pas fin de fichier
assert handle.readline() == "" # fin de fichier
handle.seek(0)
assert handle.read() == "café\n\n"
assert handle.closed
write n'ajoute pas automatiquement de fin de ligne et renvoie le nombre de
caractères écrits, pas d'octets encodés. En texte, read(size) compte les caractères ;
en binaire, les octets. En texte, tell() renvoie un marqueur de position opaque,
pas un indice de caractère général. Utilisez seek(0) pour recommencer ou une
valeur sauvegardée de tell(), plutôt que des décalages arbitraires en octets.
Avec newline=None par défaut, la lecture traduit \r, \r\n et \n en \n ;
une ligne vide reste donc distincte de la fin du fichier. a crée un fichier
absent ou ajoute au fichier existant ; r+ exige un fichier existant sans le
tronquer, tandis que w+ le tronque à l'ouverture. Aucun ne crée les répertoires
parents manquants. Fermer un fichier vide les tampons Python, sans garantir à
lui seul la persistance après une coupure de courant.