Python a une fonction prédéfinie,
open, pour ouvrir un fichier sur le disque.
open retourne un objet-fichier qui possède des
méthodes et des attributs pour obtenir des informations et manipuler
le fichier ouvert.
Exemple 6.3. Ouverture d'un fichier
>>> f = open("/music/_singles/kairo.mp3", "rb")>>> f<open file '/music/_singles/kairo.mp3', mode 'rb' at 010E3988>>>> f.mode'rb'>>> f.name'/music/_singles/kairo.mp3'
La méthode open peut prendre jusqu'à
trois paramètres : un nom de fichier, un mode et un paramètre de
tampon. Seul le premier, le nom de fichier, est nécéssaire, les
deux autres sont optionnels. Si le mode n'est
pas spécifié, le fichier est ouvert en mode texte pour la lecture.
Ici nous ouvrons le fichier en mode binaire pour la lecture
(print open.__doc__ affiche une bonne
explication de tous les modes possibles).
La fonction open retourne un objet
(arrivé à ce point cela ne
doit pas vous surprendre). Un objet-fichier à plusieurs
attributs utiles.
L'attribut mode d'un objet-fichier vous
indique dans quel mode le fichier a été ouvert.
L'attribut name d'un objet-fichier vous
indique le nom du fichier qui a été ouvert.
6.2.1. Lecture d'un fichier
Une fois un fichier ouvert, la première chose que l'on peut faire est de le lire, comme nous allons le voir dans l'exemple
suivant.
Un objet-fichier maintien des informations d'état sur le
fichier qui est ouvert. La méthode tell d'un
objet-fichier vous indique la position actuelle dans le fichier
ouvert. Comme nous n'avons encore rien fait de ce fichier la
position actuelle est 0, le début du
fichier.
La méthode seek d'un objet-fichier
permet de se déplacer dans le fichier ouvert. Le deuxième
paramètre précise ce que le premier signifie :
0 pour un déplacement à une position absolue
(en partant du début du fichier), 1 pour une
position relative (en partant de la position actuelle) et
2 pour une position relative à la fin du
fichier. Puisque les balises MP3 que nous
recherchons sont stockés à la fin du fichier, nous utilisons
2 et nous déplaçons à 128
octets de la fin du fichier.
La méthode tell confirme que la
position actuelle a changé.
La méthode read lit un nombre d'octets
spécifié du fichier ouvert et retourne une chaîne contenant les
données lues. Le paramètre optionnel précise le nombre maximal
d'octets à lire. Si aucun paramètre n'est spécifié,
read lit jusqu'à la fin du fichier. (Nous
aurions pu taper simplement read() ici, puisque
nous savons exactement où nous sommes dans le fichier et que nous
lisons en fait les 128 derniers octets.) Les données lues sont
assignées à la variable tagData et la position
actuelle est mise à jour en fonction du nombre d'octets
lus.
La méthode tell confirme que la
position actuelle a changé. Si vous faites le calcul, vous verrez
qu'après que nous ayons lu 128 octets, la position a été
incrémenté de 128.
6.2.2. Fermeture d'un fichier
Les fichiers ouverts consomment des ressources système et, en fonction du mode d'ouverture, peuvent ne pas être accessibles
à d'autres programmes. Il est donc important de fermer les fichiers dès que vous ne les utilisez plus.
Exemple 6.5. Fermeture d'un fichier
>>> f<open file '/music/_singles/kairo.mp3', mode 'rb' at 010E3988>>>> f.closedFalse>>> f.close()>>> f<closed file '/music/_singles/kairo.mp3', mode 'rb' at 010E3988>>>> f.closedTrue>>> f.seek(0)Traceback (innermost last):
File "<interactive input>", line 1, in ?
ValueError: I/O operation on closed file>>> f.tell()Traceback (innermost last):
File "<interactive input>", line 1, in ?
ValueError: I/O operation on closed file>>> f.read()Traceback (innermost last):
File "<interactive input>", line 1, in ?
ValueError: I/O operation on closed file>>> f.close()
L'attribut closed d'un objet-fichier
indique si l'objet pointe un fichier ouvert ou non. Dans ce cas,
le fichier est toujours ouvert (closed vaut
False).
Pour fermer un fichier, appelez la méthode
close de l'objet-fichier. Cela libère le
verrou (s'il existe) que vous avez sur le fichier, purge les
tampons en écriture (s'ils existent) et libère les ressources
système.
L'attribut closed confirme que le fichier est fermé.
Ce n'est pas parce que le fichier est fermé que l'objet
fichier cesse d'exister. La variable f
continuera d'exister jusqu'à ce qu'elle soit hors de portée ou
qu'elle soit supprimée manuellement. Cependant aucune des
méthodes de manipulation d'un fichier ouvert ne marchera après que
le fichier ait été fermé, elles déclencheront toutes une
exception.
Appeler close sur un objet-fichier dont
le fichier est déjà fermé ne déclenche pas
d'exception mais échoue silencieusement.
6.2.3. Gestion des erreurs d'entrée/sortie
Maintenant vous en avez vu assez pour comprendre le code de gestion de fichier dans le programme d'exemple fileinfo.py du chapitre précédent. L'exemple suivant montre comment ouvrir et lire un fichier de manière sûre en gérant les erreurs.
Comme l'ouverture et la lecture de fichiers est risquée et
peut déclencher une exception, tout ce code est enveloppé dans un
bloc try...except (alors, l'indentation standardisée
n'est-elle pas admirable ? C'est là que l'on commence a vraiment
l'apprécier).
La fonction open peut déclencher une
exception IOError (peut-être que le
fichier n'existe pas).
La méthode seek peut déclencher une
exception IOError (peut-être que le
fichier fait moins de 128 octets).
La méthode read peut déclencher une
exception IOError (peut-être que le disque
a un secteur défectueux ou le fichier est sur le réseau et le
réseau est en rideau).
Voilà qui est nouveau : un bloc
try...finally. Une fois le fichier ouvert avec
succès par la fonction open, nous voulons
être absolument sûrs que nous le refermons, même si une exception
est déclenchée par les méthodes seek ou
read. C'est à cela que sert un bloc
try...finally : le code du bloc
finally sera toujours
exécuté, même si une exception est déclenchée dans le bloc
try. Pensez-y comme à du code qui est exécuté
«au retour», quoi qu'il se soit passé «en
route».
Enfin, nous gérons notre exception
IOError. Cela peut être l'exception
IOError déclenchée par l'appel à
open, seek, ou
read. Ici, nous ne nous en soucions vraiment
pas car tout ce que nous faisons et d'ignorer l'erreur et de
continuer (rappelez-vous que pass est une
instruction Python qui ne fait rien). C'est tout
à fait légal, «gérer» une exception peut vouloir dire
explicitement ne rien faire. Cela compte quand même comme une
exception gérée et le traitement va reprendre normalement à la
prochaine ligne de code après le bloc
try...except.
6.2.4. Ecriture dans un fichier
Nous pouvons bien sûr écrire dans un fichier, cela se fait en grande partie de la même manière que pour la lecture. Il y a
deux modes d'ouverture de base :
Le mode Append (ajout) pour ajouter des données à la fin du fichier.
Le mode Write (écriture) pour écraser le contenu du fichier.
Les deux modes créeront le fichier automatiquement s'il n'existe pas encore, il n'y a donc pas besoin de logique du type «si le fichier de journalisation n'existe pas, créer un nouveau fichier vide et l'ouvrir en écriture.» Il suffit d'ouvrir le fichier pour commencer à y écrire.
Nous commençons par créer un nouveau fichier test.log ou l'écraser s'il existe et l'ouvrir en écriture (le second paramètre "w" signifie ouverture en écriture). Effectivement, c'est aussi dangeureux que ça en a l'air. J'espère que vous n'aviez rien
de précieux dans ce fichier, parce que maintenant c'est effacé.
Vous pouvez écrire dans le fichier ouvert à l'aide de la méthode write de l'objet-fichier retourné par open.
file est un synonyme de open. Ici, nous ouvrons le fichier, lisons son contenu et l'imprimons en une seule ligne.
Nous savons que test.log existe (puisque nous venons juste d'écrire dedans), donc nous pouvons l'ouvrir pour ajouter des données (le paramètre "a" signifie ouverture pour ajout). En fait, nous pourrions le faire même si le fichier n'existait pas, puisque l'ouverture du
fichier en mode ajout crée le fichier si nécéssaire. Mais le mode ajout n'endommagera jamais le contenu du fichier.
Comme vous pouvez le voir, la ligne d'origine aussi bien que la nouvelle ligne ajoutée sont maintenant dans test.log. Notez également que le retour à la ligne n'est pas inclus. Puisque nous n'en avons pas explicitement écrit dans le fichier,
le fichier n'en contient pas. Nous pouvons écrire un retour à la ligne avec le caractère "\n". Puisque nous ne l'avons pas fait, tout ce que nous avons écrit finit sur la même ligne.