python fichier

Identification

Infoforall

32 - Enregister et lire des fichiers


Comment enregistre-t-on des données dans un fichier texte ? Et d'ailleurs, qu'est-ce qu'un fichier ?

Logiciel nécessaire pour l'activité : Python 3 : Thonny, IDLE ...

Evaluation ✎ : questions 10-11-12-13-14-15-16

Documents de cours : open document ou pdf

1 - Création d'un fichier

01° Voici un script permettant de créer un fichier texte. Suivre les instructions et questions décrites ci-dessous.

  1. Créer un répertoire qu'on nommera activiteFichier.
  2. Enregistrer ce script de le répertoire activiteFichier.
  3. 📁 activiteFichier

    📄 script_test.py

    1 2 3 4 5 6 7 8 9
    # 1 - Création de l'objet-fichier : ouverture en mode w (write) obj_fichier = open('aaa.txt', 'w', encoding="utf-8") # 2 - Remplissage progressif du fichier obj_fichier.write("Premier contenu") obj_fichier.write("Deuxième ajout") # 3 - Fermeture de l'objet-fichier obj_fichier.close()
  4. Utiliser le script. Regarder le contenu de votre répertoire : vous devriez constater la présence d'un nouveau fichier nommée 'aaa.txt' dans votre répertoire.
  5. 📁 activiteFichier

    📄 script_test.py

    📄 aaa.txt

  6. Pourquoi le fichier est-il créé dans le même répertoire que le fichier Python ?

...CORRECTION...

Tout simplement car on ne donne que le nom du fichier à créer.

Il s'agit donc d'une adresse relative, relative à l'endroit où se trouve le fichier Python.

Relative à l'endroit où se situe le fichier contenant l'appel à open(). Le fichier texte est donc créé dans le même répertoire que celui du programme.

02° Ouvrir le fichier-texte pour voir son contenu. Que voyez-vous de surprenant ?

...CORRECTION...

Voici le contenu :

Première ligneDeuxième ligne

On constate donc qu'il n'y a pas de passage à la ligne. Alors qu'on aurait pu le croire. La méthode write() porte donc bien son nom : elle écrit des octets dans le fichier. Si on ne signale pas qu'il faut insérer l'octet signalant le passage à la ligne, la méthode ne le rajoute pas automatiquement. Elle fait simplement ce qu'on lui demande.

La méthode write() ne fait que rajouter le contenu, sans chercher à rajouter de passage à la ligne.

Si vous voulez rajouter les passages à la ligne, il faudra le dire, en rajoutant des passages à la ligne  \n  dans votre string une fois que vous avez fini une ligne.

03° Tester le script suivant dans lequel nous tentons cette fois de rajouter des passages à la ligne. Ouvrir le fichier-texte après avoir exécuté le script.

1 2 3 4 5 6 7 8 9
# 1 - Création de l'objet-fichier : ouverture en mode w (write) obj_fichier = open('aaa.txt', 'w', encoding="utf-8") # 2 - Remplissage progressif du fichier obj_fichier.write("Voici une nouvelle ligne\n") obj_fichier.write("Cette fois, c'est la dernière ligne du fichier.\n") # 3 - Fermeture de l'objet-fichier obj_fichier.close()

Question

Qu'est devenu l'ancien contenu ?

...CORRECTION...

Voici le contenu :

Voici une nouvelle ligne Cette fois, c'est la dernière ligne du fichier.

Chose surprenante : le nouveau contenu a supprimé le premier contenu !

Alors comment faire pour rajouter du contenu sans supprimer l'ancien ?

1.1 Créer un fichier-texte avec la fonction open()

Création avec open()

Pour écrire dans un fichier-texte, il faut commencer par l'ouvrir avec la fonction open() : cette fonction permet de créer un objet-fichier dont on va pouvoir utiliser la référence pour interagir avec le vrai contenu en mémoire.

Open avec l'option "w", le mode write (écrasement)
1
obj_fichier = open('aaa.txt', 'w', encoding="utf-8")

Cela crée l'objet-fichier obj_fichier mais en supprimant tout le contenu éventuel précédent.

On utilise ce mode lorsqu'on veut créer un nouveau contenu.

Open avec l'option "a", le mode append (rajout)
1
obj_fichier = open('aaa.txt', 'a', encoding="utf-8")

Cela crée l'objet-fichier obj_fichier mais en récupérant l'ancien contenu s'il existe.

Comme pour les tableaux dynamiques (type list en Python), "append" veut dire qu'on rajoute le contenu à la fin du contenu précédent.

On utilise ce mode lorsqu'on veut rajouter du contenu sans perdre l'ancienne information.

1.2 Rajout de contenu avec la méthode write()

On utilise la notation avec le point qu'on utilise sur les objets : fichier-objet.méthode().

Ceci ajoute le texte "Bonjour" dans l'objetfichier MAIS sans passer à la ligne, ni avant, ni après.

2
obj_fichier.write("Bonjour")

Si vous voulez ajouter un passage à la ligne, il faudra l'indiquer à l'aide de la présence du caractère  \n  dans la chaîne.

2
obj_fichier.write("Voici une nouvelle ligne\n")
1.3 Fermeture de l'objet-fichier avec la méthode close()

3
obj_fichier.close()

Attention : si la fermeture est mal effectuée, ou pas effectuée, cela peut entrainer des problèmes lors d'une prochaine ouverture. Pensez donc bien à fermer votre objet.

04° Créer un script qui permet cette fois de rajouter deux lignes au fichier 'aaa.txt' sans pour autant supprimer le texte déjà enregistré.

...CORRECTION...

Le fichier est déjà créé. Il suffit donc d'utiliser l'argument 'a' et pas l'argument 'w.

1 2 3 4 5 6 7 8 9
# 1 - Création de l'objet-fichier : ouverture en mode a (append) obj_fichier = open('aaa.txt', 'a', encoding="utf-8") # 2 - Remplissage progressif du fichier obj_fichier.write("Et cette fois, on supprime ou pas ?\n") obj_fichier.write("Ah ben non. On rajoute.\n") # 3 - Fermeture de l'objet-fichier obj_fichier.close()

Voici le contenu obtenu après exécution :

Voici une nouvelle ligne Cette fois, c'est la dernière ligne du fichier. Et cette fois, on supprime ou pas ? Ah ben non. On rajoute.

Nous savons donc maintenant créer un fichier-texte ou rajouter des caractères à la suite des précédents.

1.4 Exemple d'écriture dans un fichier

Exemple où on remplace intégralement le contenu d'un fichier.

1 2 3 4 5 6 7 8 9
# 1 - Création de l'objet-fichier : ouverture en mode w (write) obj_fichier = open('aaa.txt', 'w', encoding="utf-8") # 2 - Remplissage progressif du fichier obj_fichier.write("Premier contenu") obj_fichier.write("Deuxième ajout") # 3 - Fermeture de l'objet-fichier obj_fichier.close()

Exemple où on rajoute à la fin du fichier, sans écraser l'ancien contenu.

1 2 3 4 5 6 7 8 9
# 1 - Création de l'objet-fichier : ouverture en mode w (write) obj_fichier = open('aaa.txt', 'a', encoding="utf-8") # 2 - Remplissage progressif du fichier obj_fichier.write("Voici une nouvelle ligne\n") obj_fichier.write("Cette fois, c'est la dernière ligne du fichier.\n") # 3 - Fermeture de l'objet-fichier obj_fichier.close()
Saut à la ligne avec Windows

La lecture d'un fichier-texte issu de Windows montre parfois la présence d'un caractère particulier en plus de  \n  : le caractère d'échappement retour-chariot  \r  (octet contenant 13 en ASCII).

2 - Lecture d'un fichier

Voyons comment lire les caractères de notre fichier.

Cette fois, nous allons l'ouvrir avec l'argument 'r' pour READ. La liaison sera ainsi effectuée uniquement en lecture.

Nous allons voir :

  1. Comment lire une ligne à la fois avec readline()
  2. Comment lire toutes les lignes readline() dans une boucle TANT QUE
  3. Comment lire toutes les lignes readline() dans une boucle POUR
  4. Comment lire un caractère à la fois avec read()
  5. Comment gérer l'encodage utilisé sur le fichier-texte
2.1 Lecture manuelle d'une ligne avec la méthode readline()

Lorsqu'on ouvre un fichier-objet, Python génère une tête de lecture qui pointe initialement au début du fichier-texte.

La méthode readline() renvoie un string contenant la prochaine ligne qu'on peut lire à partir de la position actuelle de la tête de lecture du fichier-objet. Elle renvoie dans le string situé entre

  • La tête de lecture
  • Le prochain \n (Line Feed, 10 en ASCII) ou la fin du fichier (EOF, End Of File)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# 1 - Création de l'objet-fichier : ouverture en mode r (read) obj_fichier = open('aaa.txt', 'r', encoding="utf-8") # 2 - Lecture progressive du fichier a = obj_fichier.readline() print(a, end="") b = obj_fichier.readline() print(b, end="") c = obj_fichier.readline() print(c, end="") d = obj_fichier.readline() print(d, end="") # 3 - Fermeture de l'objet-fichier obj_fichier.close()

Voici un exemple de résultat :

Voici une nouvelle ligne Cette fois, c'est la dernière ligne du fichier. Et cette fois, on supprime ou pas ? Ah ben non. On rajoute.

Ici, chaque ligne sera simplement affichée sur la console à l'aide de la fonction native print(). Pourquoi avoir rajouté end="" ?

Tout simplement car le \n fait partie du string renvoyé. Si vous ne modifiez pas la fin du print(), vous aurez deux passages à la ligne : celui à l'intérieur du string et celui généré par défaut par print().

>>> a 'Voici une nouvelle ligne\n' >>> b 'Cette fois, c'est la dernière ligne du fichier.\n' >>> c 'Et cette fois, on supprime ou pas ?\n' >>> c 'Ah ben non. On rajoute.\n'

05° Utiliser le script suivant puis rajouter quelques autres lectures de façon à tenter de lire plus de lignes que le fichier n'en possède.

Questions

  1. Quel est le string qu'on récupère lorsqu'on lit alors qu'on se trouve à la fin du fichier ?
  2. Python déclenche-t-il une erreur lorsqu'on va 'trop loin' ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# 1 - Création de l'objet-fichier : ouverture en mode r (read) obj_fichier = open('aaa.txt', 'r', encoding="utf-8") # 2 - Lecture progressive du fichier a = obj_fichier.readline() print(a, end="") b = obj_fichier.readline() print(b, end="") c = obj_fichier.readline() print(c, end="") d = obj_fichier.readline() print(d, end="") # 3 - Fermeture de l'objet-fichier obj_fichier.close()

...CORRECTION...

La fin de fichier est représenté par un string vide "".

Une fois en fin de fichier, on peut tenter de lire autant de lignes qu'on veut, on n'obtient pas une erreur mais on lit simplement encore et encore un string vide "".

Avec cette façon de faire, si on a 1500 lignes, on est parti pour taper 1500 fois readline()...

Heureusement, notre objet-fichier obj_fichier est un itérable : on peut utiliser une boucle FOR pour lire ses éléments un par un.

Je présente ci-dessous deux manières de lire toutes les lignes d'un fichier-texte en utilisant une boucle.

2.2 Boucle while avec la méthode readline()

Principe
  • On lit et enregistre une première ligne
  • TANT QUE la ligne n'est pas vide
    • On fait le traitement de cette ligne
    • On lit et enregistre la ligne suivante
  • Fin du TANT QUE

Il faudra donc veiller à initialiser la variable de boucle avec quelque chose qui permette de rentrer une première fois dans la boucle.

Exemple
1 2 3 4 5 6 7 8 9 10 11 12
# 1 - Création de l'objet-fichier : ouverture en mode r (read) obj_fichier = open('aaa.txt', 'r', encoding="utf-8") # 2 - Lecture ligne par ligne ligne = obj_fichier.readline() while ligne != "": print(ligne, end="") # Traitement de la ligne actuelle ligne = obj_fichier.readline() # Lecture et stockage de la ligne suivante # 3 - Fermeture de l'objet-fichier obj_fichier.close()

06° Utiliser ce script de lecture : il va vous permettre de lire et afficher en boucle les "lignes" du fichier.

1 2 3 4 5 6 7 8 9 10 11 12
# 1 - Création de l'objet-fichier : ouverture en mode r (read) obj_fichier = open('aaa.txt', 'r', encoding="utf-8") # 2 - Lecture ligne par ligne ligne = obj_fichier.readline() while ligne != "": print(ligne, end="") ligne = obj_fichier.readline() # 3 - Fermeture de l'objet-fichier obj_fichier.close()

Questions

  1. Quelles sont les 3 lignes qui appartiennent au TANT QUE ?
  2. Comment traduire en français ces trois lignes ?
  3. A quoi sert la ligne 5 ?

...CORRECTION...

  1. Il s'agit des lignes 7-8-9.
  2. 7 8 9
    while ligne != "": print(ligne, end="") ligne = obj_fichier.readline()
  3. Voici une traduction possible de ces lignes :
  4. L7 : Tant qu'on n'a pas atteint la fin du fichier.

    L8 : Afficher cette ligne (sans rajouter de passage à la ligne, il est intégré dans le string de la ligne)

    L9 : lire et stocker la ligne suivante.

  5. La ligne 5 permet simplement de créer une première ligne à lire. Si elle n'est pas vide, on réalisera donc la boucle. Si elle est vide dès le départ, on ne réalisera même pas un tour de boucle.

07° Tester cette nouvelle version. La seule différence se trouve en ligne 7.

Question

  • Que signifie la nouvelle condition ?
1 2 3 4 5 6 7 8 9 10 11 12
# 1 - Création de l'objet-fichier : ouverture en mode r (read) obj_fichier = open('aaa.txt', 'r', encoding="utf-8") # 2 - Lecture ligne par ligne ligne = obj_fichier.readline() while ligne: print(ligne, end="") # Traitement de la ligne actuelle ligne = obj_fichier.readline() # Lecture et stockage de la ligne suivante # 3 - Fermeture de l'objet-fichier obj_fichier.close()

...CORRECTION...

L'interpréteur Python interprète l'expression derrière le while comme un booléen, même si cette expression ne l'est pas.

Il suffit de se souvenir qu'en Python :

  • False, c'est tout ce qui est nul ou vide.
  • True, c'est... tout le reste.

La condition de poursuite veut donc dire de continuer si ligne contient autre chose que 0, False, None, une chaîne vide ou un tableau non vide, ou un dictionnaire non vide ou un tuple non vide...

Puisque ligne est un string, cela veut donc dire de continuer TANT QUE la ligne contient quelque chose.

2.3 Boucle while avec la méthode readline() V2

Evaluer un non-booléen en booléen en Python

!!! A SAVOIR PAR COEUR !!!

En Python, un contenu VIDE ou NUL est évalué à False si on demande un résulat booléen.

Dans tous les autres cas, le résultat est True.

Conséquence sur la condition de poursuite

On obtient donc un code encore plus simple que le précédent :

1 2 3 4 5 6 7 8 9 10 11 12
# 1 - Création de l'objet-fichier : ouverture en mode r (read) obj_fichier = open('aaa.txt', 'r', encoding="utf-8") # 2 - Lecture ligne par ligne ligne = obj_fichier.readline() while ligne: print(ligne, end="") # Traitement de la ligne actuelle ligne = obj_fichier.readline() # Lecture et stockage de la ligne suivante # 3 - Fermeture de l'objet-fichier obj_fichier.close()

L'objet-fichier est un itérable en Python : nous allons donc pouvoir utiliser un POUR.

2.4 Boucle for avec la méthode readline()

Principe
  • On lit l'une des lignes à chaque tour de boucle

Et c'est tout.

C'est comme lire une à une les valeurs d'un tableau.

Ici, on lit une à une les lignes du fichier.

Exemple
1 2 3 4 5 6 7 8 9
# 1 - Création de l'objet-fichier : ouverture en mode w obj_fichier = open('aaa.txt', 'r', encoding="utf-8") # 2 - Remplissage progressif du fichier for ligne in obj_fichier: print(ligne, end="") # 3 - Fermeture de l'objet-fichier obj_fichier.close()

Le plus explicite est donc de nommer la variable de boucle ligne plutôt que k, x ou autre, puisqu'elle va contenir l'une des lignes, une par tour de boucle.

08° Utiliser ce script de lecture : il va vous permettre de lire et afficher en boucle les "lignes" du fichier.

En ligne 2, on notera qu'on demande le type de l'objet-fichier obj_fichier.

Question : quel est son type ? est-ce un simple texte ?

1 2 3 4 5 6 7 8 9 10
# 1 - Création de l'objet-fichier : ouverture en mode w obj_fichier = open('aaa.txt', 'r', encoding="utf-8") print(type(obj_fichier)) # 2 - Remplissage progressif du fichier for ligne in obj_fichier: print(ligne, end="") # 3 - Fermeture de l'objet-fichier obj_fichier.close()

...CORRECTION...

Cet objet est de type TextIOWrapper. Il s'agit d'un objet gestionnaire de flux entrant (input)-sortant(output). Il ne s'agit donc pas directement du texte ou du fichier mais d'un objet informatique permettant d'interagir avec le fichier dont les octets sont enregistrés en mémoire.

obj_fichier est un objet capable de faire interface entre notre programme et le fichier réel (la suite d'octets).

On peut également lire les caractères un par un avec la méthode read() qui permet de lire le flux de données en fonction d'un nombre de caractères plutôt que d'aller nécessairement jusqu'au prochain passage à la ligne /n.

2.5 Lire un caractère à la fois avec la méthode read()

Principe

La méthode read() lit le flux de données en fonction d'un nombre de caractères plutôt que d'aller nécessairement jusqu'au prochain passage à la ligne /n.

On lui fournit en argument le nombre de caractères à lire. Si on ne précise pas d'argument, la méthode va renvoyer... la totalité du flux.

Exemple

Voici un script de lecture qui vous permettra de lire les caractères enregistrés dans le fichier un par un. On affiche chaque caractère, à part les  a  ou les  A  qu'on décide de remplacer par  @ .

On utilise un print() dont le caractère final est une étoile, de façon à bien voir les successions de lecture.

10
print(lecture, end="*")

Voici le script :

1 2 3 4 5 6 7 8 9 10 11 12 13
# 1 - Création de l'objet-fichier : ouverture en mode w obj_fichier = open('aaa.txt', 'r', encoding="utf-8") # 2 - Remplissage progressif du fichier lecture = "o" # Affectation quelconque pour rentrer une première fois dans la boucle while lecture: lecture = obj_fichier.read(1) if lecture == 'a' or lecture == 'A': lecture = '@' print(lecture, end="*") # 3 - Fermeture de l'objet-fichier obj_fichier.close()

09° Utiliser le script présenté ci-dessus et visualiser le résultat.

Questions

  1. A quoi voit-on que l'espace est bien un caractère comme un autre ?
  2. A quoi voit-on que le LINE FEED est bien un caractère comme un autre ?
  3. Modifier alors le programme pour qu'il fournisse des blocs de 5 caractères à la fois.

...CORRECTION...

On obtient cet affichage :

V*o*i*c*i* *u*n*e* *n*o*u*v*e*l*l*e* *l*i*g*n*e* *C*e*t*t*e* *f*o*i*s*,* *c*'*e*s*t* *l*@* *d*e*r*n*i*è*r*e* *l*i*g*n*e* *d*u* *f*i*c*h*i*e*r*.* *E*t* *c*e*t*t*e* *f*o*i*s*,* *o*n* *s*u*p*p*r*i*m*e* *o*u* *p*@*s* *?* *@*h* *b*e*n* *n*o*n*.* *O*n* *r*@*j*o*u*t*e*.* **

On voit bien que l'espace est un caractère puisqu'il y a apparition d'une étoile derrière chaque caractère dans le code et que derrière les espaces on trouve bien ... une étoile.

Idem pour les passages à la ligne (LINE FEED) : le caractère provoque le passage à la ligne car c'est un caractère de contrôle et pas juste un caractère d'imprimerie. Ici, on constate donc qu'il y a une étoile en début de chaque nouvelle ligne. Le LINEFEED est donc bien un caractère.

Si on lance le code en lisant 5 caractères à la fois en ligne 7, on obtient ceci :

Voici* une *nouve*lle l*igne *Cette* fois*, c'e*st la* dern*ière *ligne* du f*ichie*r. Et* cett*e foi*s, on* supp*rime *ou pa*s ? A*h ben* non.* On r*ajout*e. **

Une dernière chose avec la lecture : pour lire un fichier-texte, il faut en réalité se rendre compte qu'on lit des octets et qu'on les décode en respectant un certain encodage.

Ici, nous avons créé le fichier en utilisant l'encodage UTF-8 (de 1 à 4 octets par caractère). Il faudrait donc le lire en décodant le fichier en UTF-8 également.

✎ 10° Réaliser les tâches suivantes 

  1. Mettre en mémoire, lire mentalement et utiliser le script suivant qui

    • crée un fichier en UTF-8 puis le ferme (sur les lignes 2-3-4)
    • lit ce fichier en UFT-8 puis le ferme (sur les lignes 7-8-9-10).
    1 2 3 4 5 6 7 8 9 10
    # 1 - Ecriture du fichier obj_fichier = open('perceval.txt', 'w', encoding="utf-8") obj_fichier.write("C'est écrit en UTF-8 ?\nDe toutes manières, j'ai jamais rien compris à vos histoires d'encodage.") obj_fichier.close() # 2 - lecture du fichier obj_fichier = open('perceval.txt', 'r', encoding="utf-8") for ligne in obj_fichier: print(ligne) obj_fichier.close()

    Ci-dessous le résultat attendu à l'affichage :

    Affichage avec écriture en UTF-8 et lecture en UTF-8 :

    C'est écrit en UTF-8 ? De toutes manières, j'ai jamais rien compris à vos histoires d'encodage.
  2. Fournir sur votre copie la modification suivante du programme : il doit créer le fichier en UTF-8 mais le lire en iso8859_15 (également nommée latin9 ou latin-9). Il s'agit de la table ASCII étendu (un octet) pour l'europe de l'Ouest. Fournir le code du nouveau script sur votre copie.
  3. Affichage attendu avec écriture en UTF-8 et lecture en iso8859_15 :

    C'est écrit en UTF-8 ? De toutes maniÚres, j'ai jamais rien compris à vos histoires d'encodage.
  4. Lancer le programme pour observer que votre affichage correspond bien à celui qui est représenté ci-dessus.
  5. Les caractères de base (ceux qui ASCII) sont-ils bien lus ? Quels sont les caractères qui semblent poser problèmes lorsqu'il n'y a pas correspondance entre encodage d'écriture et encodage de lecture ?

3 - Taille des fichiers

✎ 11° Créer un script qui permet de créer un fichier-texte contenant le texte suivant en l'encodant en iso8859_15.

texte = "Ce court texte a été créé en considérant le fait qu'on a besoin de caractères peu courants lorsqu'on veut comparer les tailles obtenues avec différents encodages, à savoir le fait que la plus petite taille sera obtenue avec les tables 1 octet et la plus grande taille avec utf-32"

Vérifier que la taille du fichier-texte est de 279 octets : après création par votre programme python, faire un clic-droit sur le fichier-texte et rechercher sa taille dans les propriétés.

✎ 12° Modifier le script de façon à créer le même fichier-texte mais en utilisant différents encodages.

Questions

  1. Quelle est la taille du fichier-texte encodé en utf-8 ?
  2. Quelle est la taille du fichier-texte encodé en utf-16 ?
  3. Quelle est la taille du fichier-texte encodé en utf-32 ?
Taille des fichiers-texte

Les fichiers-texte encodés en ASCII étendu pèsent un octet par caractère.

Les fichiers-texte encodés en UTF-8 pèsent à peine plus si les caractères sont principalement des fichiers ASCII.

Les fichiers-texte encodés en UTF-16 pèsent deux fois plus environ.

Les fichiers-texte encodés en UTF-32 pèsent quatre fois plus que le fichier en ASCII étendu.

4 - [Compléments Strings]

Maintenant vous savez

  1. créer des fichiers (avec 'w'),
  2. rajouter des choses dans les fichiers (avec 'a') et
  3. lire les fichiers avec (avec 'r')

Une fois lu dans Python, ces textes se retrouvent stocker dans des strings. Il est donc important de connaître quelques manipulations basiques avec des strings.

(Rappel) 4.1 STRING : mot-clés in et not in

Test d'appartenance ou de présence

On utilise l'opérateur binaire in qui renvoie un booléen.

Pour savoir si le string contenu est présent dans le string s, on tape contenu in s.

>>> "bon" in "bonjour" True >>> "Bon" in "bonjour" False

Traduction : "bon" est-il présent dans "bonjour" ? "Bon" est-il présent dans "Bonjour" ?

Test de non-appartenance ou d'absence

On utilise l'opérateur binaire not in qui renvoie un booléen.

Pour savoir si le string contenu n'est pas présent dans le string s, on tape contenu not in s.

>>> "bon" not in "bonjour" False >>> "Bon" not in "bonjour" True

Traduction : "bon" est-il absent de "bonjour" ? "Bon" est-il absent de "Bonjour" ?

4.2 STRING : méthode endswith()

Tester si un string fini par .txt ?

C'est toujours pratique de vérifier l'extension d'un fichier.

Il existe une méthode endswith() des strings qui sert à ça :

>>> nom = 'perceval.txt' >>> nom.endswith('.txt') True >>> nom.endswith('.png') False

On peut aussi juste vérifier que les 4 derniers caractères correspondent bien à .txt.

>>> nom = "perceval.txt" >>> nom[-4:] == '.txt' True >>> nom[-4:] == '.png' False
4.3 STRING : méthodes lower() upper()

Transformer un string en majuscules ou en minuscules ?

Pratique pour vérifier si un texte contient le nom Toto sans tester toto, TOTO et Toto...

On peut utiliser les méthodes upper et lower qui renvoie une copie du string.

Regardez bien la majuscule dans le nom suivant :

>>> nom = "Merlin ou Toto l'asticot" >>> 'toto' in nom False >>> 'toto' in nom.lower() True >>> nom "Merlin ou Toto l'asticot"
4.4 strlist avec list() : récupérer les caractères

Un string est un conteneur de caractères.

On peut donc les placer dans un autre conteneur, par exemple un tableau.

Pour cela, le plus simple est d'utiliser la fonction native list() qui tente de créer un tableau à partir des données fournies en entrée.

Récupérer les caractères dans un tableau

Il suffit d'utiliser la fonction native list().

>>> nom = "Merlin ou Toto l'asticot" >>> t = list(nom) >>> t ['M', 'e', 'r', 'l', 'i', 'n', ' ', 'o', 'u', ' ', 'T', 'o', 't', 'o', ' ', 'l', "'", 'a', 's', 't', 'i', 'c', 'o', 't']
4.5 strlist avec split() récupérer les éléments structurants d'un string

Une phrase est un ensemble de mots séparés par des espaces notamment.

La méthode split() veut dire séparer et permet justement de "séparer" un string en différentes parties et placer ces parties dans un tableau.

Récupérer les mots d'une phrase

On utilise la méthode split() en précisant que le caractère de séparation est l'espace.

>>> nom = "Merlin ou Toto l'asticot" >>> t = nom.split(' ') >>> t ['Merlin', 'ou', 'Toto', "l'asticot"]
Spliter sans rien fournir

Par défaut, il est possible de ne pas préciser le caractère qui servira à scinder le string en plusieurs parties : la méthode est configurée pour considérer qu'il s'agit de l'espace.

>>> nom = "Merlin ou Toto l'asticot" >>> t = nom.split() >>> t ['Merlin', 'ou', 'Toto', "l'asticot"]
Récupérer les phrases ?

Pour récupérer les phrases, on peut considérer qu'il suffit d'utiliser la méthode en considérant que le caractère séparateur est le point.

4.6 STRING : récupérer dans un tableau les colonnes d'une ligne CSV

Récupérer les informations dans une ligne d'un fichier CSV

Dans un fichier CSV :

  • chaque ligne du fichier est un enregistrement
  • chaque ligne est constituée d'informations séparées par des virgules ou des points-virgules.

Pour les séparer, il suffit d'utiliser la méthode split() en précisant que le caractère de séparation est le point-virgule par exemple.

>>> ligne = "Merlin;magicien;999 ans;Forêt de Brocéliande/n" >>> t = ligne.split(';') >>> t ['Merlin', 'magicien', '999 ans', 'Forêt de Brocéliande/n']
4.7 STRING : méthode replace()

Remplacer un caractère par un autre

Attention, on ne modifie pas le string initial (il est immmuable !). On renvoie juste une copie modifiée.

>>> texte = "Toto" >>> modif = texte.replace("o", "i") >>> modif 'Titi'
Supprimer les passages à la ligne

Pratique par exemple pour supprimer les /n reçus dans un string.

>>> ligne = "Merlin;magicien;999 ans;Forêt de Brocéliande/n" >>> ligne_bis = ligne.replace("/n", "") >>> ligne_bis 'Merlin;magicien;999 ans;Forêt de Brocéliande/n' >>> t = ligne_bis.split(";") >>> t ['Merlin', 'magicien', '999 ans', 'Forêt de Brocéliande']

✎ 13° Réaliser les tâches suivantes :

  1. Lancer ce programme et faire au moins trois enregistrements
  2. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
    fichier = open('musique.csv', 'a', encoding='utf-8') continuer = "o" while continuer.lower() != 'n': titre = input("Entrer le titre de la chanson : ") artiste = input("Entrer le nom du chanteur / groupe : ") sortie = input("Date de sortie (format MM-AAAA) : ") genre = input("Genre musical : ") note = input("Votre notation (de 0 (nul) à 5 (excellent)") url = input("Obligatoire : une URL pour l'écouter ou avoir des infos") enregistrement = f"{titre};{artiste};{sortie};{genre};{note};{url}" fichier.write(enregistrement+'\n') continuer = input("Nouvelle entrée (O/N) ? ") fichier.close()
  3. Localiser le fichier créé après être sorti de la boucle. Cliquer dessus : vous devriez voir qu'un fichier texte CSV est un format compréhensible pour un tableur.
  4. Expliquer ce que fait ce programme étape par étape.
  5. Analyser la ligne 5 avec précision : dans quels cas parvient-on à sortir de la boucle ? Décrire les réponses possibles permettant de sortir de la boucle.
  6. Qu'aurions-nous pu mettre à la place de "o" en ligne 3 ?

✎ 14° Qu'est-ce que le format CSV, Comma Separated Value ?

  • A : Un format libre de musique, une alternative à MP3.
  • B : Un format texte permettant de comprimer les données.
  • C : Un format d'enregistrement simple de données où chaque enregistrement prend une ligne et où les éléments sont séparés par des virgules
  • D : Il y a une faute dans l'énoncé. C'est Coma Separated Value en réalité. C'est un format de données presque abandonné, comateux.

On demande d'enregistrer des choses. C'est fait. Mais comment les lire ?

✎ 15° Fournir un programme capable de lire et afficher ligne par ligne les enregistrements dans le fichier CSV que nous venons de créer. Vous réaliser d'abord un affichage brut de la ligne.

Modifier ensuite votre programme : en utilisant la méthode split() pour séparer les différentes informations placées sur la ligne, afficher correctement les informations de chaque morceau de musique.

Pour cela, aller lire les rappels ci-dessus dont voici un cours résumé :

>>> entree = "aaa;bbb;ccc;ddd" >>> champs = entree.split(";") >>> champs ['aaa', 'bbb', 'ccc', 'ddd'] >>> champs[0] 'aaa'

5 - [HORS PROGRAMME] Lecture octet par octet

Cette partie ne vise qu'à vous montrer ce qu'est en réalité un fichier (texte ou pas). Rien n'est à retenir par coeur.

Vous avez certainement déjà compris le principe du fichier en tant que suite d'octets. Nous allons ici manipuler le concept pour bien l'appréhender.

Nous avons vu que votre fichier n'est au final qu'une suite d'octets.

Ca tombe bien : Python est capable de lire les octets du fichier plutôt que de tenter de les interpréter-décoder sous forme d'un texte. Pour cela, il faut créer votre objet-fichier avec un argument contenant 'r', comme binaire. Ainsi pour lire les octets, il suffit d'ouvrir le fichier avec 'rb'.

Nous utiliserons deux méthodes :

  • la méthode read() qui permet de lire un certain nombre d'octets dans le flux.
  • la méthode tell() qui renvoie la position du pointeur sur le fichier.

16° Utiliser ce script qui crée un fichier en l'encodant en iso8859_15 et qui l'ouvre ensuite en lecture binaire de façon à voir le contenu octet par octet.

On utilise l'affichage Python usuel des bytes : si la valeur est inférieure à 128, on affiche le caractère ASCII correspondant.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
# Création et fermeture du fichier fichier = open('lecture.txt', 'w', encoding="iso8859_15") fichier.write("Dernière partie.\n") fichier.close() # Ouverture du fichier en mode byte fichier = open('lecture.txt', 'br') # Affichage en utilisant l'affichage standard des bytes en Python octet = b'0' while octet: position = fichier.tell() # On mesure la position du pointeur de lecture octet = fichier.read(1) # On lit un octet dans le flux if octet: print(f"Position dans le fichier {position}. Lecture : ", octet) # Fermeture du fichier fichier.close()

17° Questions :

  1. Ligne 5 : Qu'est-ce qui montre qu'on ouvre le fichier en mode binaire et pas en mode texte ?
  2. Ligne 8 : pourquoi créer une variable octet à cette endroit pour y mettre "n'importe quoi" ?
  3. Combien d'octets dans ce fichier ?

...CORRECTION...

Ligne 5 : Il s'agit de l'indication 'rb' : r pour read et b pour byte.

Ligne 8 : il s'agit simplement de pouvoir rentrer une première fois dans la boucle non bornée while.

En comptant manuellement, on voit que le fichier est composé de 17 octets.

Position dans le fichier 0. Lecture : b'D' Position dans le fichier 1. Lecture : b'e' Position dans le fichier 2. Lecture : b'r' Position dans le fichier 3. Lecture : b'n' Position dans le fichier 4. Lecture : b'i' Position dans le fichier 5. Lecture : b'\xe8' Position dans le fichier 6. Lecture : b'r' Position dans le fichier 7. Lecture : b'e' Position dans le fichier 8. Lecture : b' ' Position dans le fichier 9. Lecture : b'p' Position dans le fichier 10. Lecture : b'a' Position dans le fichier 11. Lecture : b'r' Position dans le fichier 12. Lecture : b't' Position dans le fichier 13. Lecture : b'i' Position dans le fichier 14. Lecture : b'e' Position dans le fichier 15. Lecture : b'.' Position dans le fichier 16. Lecture : b'\n'

L'affichage des bytes de cette façon ne permet pas de voir clairement que ce sont juste des octets.

Nouveau programme : on affiche le contenu trois fois de suite :

  • Une première fois en les affichant avec le principe de Python.
  • Une deuxième fois en obtenant leurs valeurs en base 10
  • Une troisième fois en affichant leurs valeurs en base 16

Les seules différences entre les trois tient dans la façon d'afficher l'octet.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
# Création et fermeture du fichier fichier = open('lecture.txt', 'w', encoding="iso8859_15") fichier.write("Dernière partie.\n") fichier.close() # Ouverture du fichier en mode byte fichier = open('lecture.txt', 'br') # Affichage en utilisant l'affichage standard des bytes en Python octet = b'0' while octet: position = fichier.tell() # On mesure la position du pointeur de lecture octet = fichier.read(1) # On lit un octet dans le flux if octet: print(f"Position dans le fichier {position}. Lecture : ", octet) # Affichage en affichant les valeurs décimales octet = b'0' while octet: position = fichier.tell() # On mesure la position du pointeur de lecture octet = fichier.read(1) if octet: print(f"Position dans le fichier {position}. Lecture : ", octet[0]) # Affichage en affichant les valeurs hexadécimales octet = b'0' while octet: position = fichier.tell() # On mesure la position du pointeur de lecture octet = fichier.read(1) if octet: print(f"Position dans le fichier {position}. Lecture : ", hex(octet[0])) # Fermeture du fichier fichier.close()

18° Utiliser le programme précédent.

Question

Pourquoi UN SEUL AFFICHAGE ?

...CORRECTION...

Simplement car à chaque utilisateur du read on se déplace de un octet. Au bout d'un moment, nous arrivons donc... à la fin du fichier !

Lorsqu'on arrive en ligne 21 ou 29, on est déjà en fin de fichier. La lecture ne renvoit donc rien.

Comment faire alors ? Il faut revenir en arrière. Pour cela, il existe une méthode nommée seek. On lui transmet en argument la position à laquelle on veut placer le pointeur de fichier.

Ici, on veut le remettre à zéro, revenir au début du fichier.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
# Création et fermeture du fichier fichier = open('lecture.txt', 'w', encoding="iso8859_15") fichier.write("Dernière partie.\n") fichier.close() # Ouverture du fichier en mode byte fichier = open('lecture.txt', 'br') # Affichage en utilisant l'affichage standard des bytes en Python octet = b'0' while octet: position = fichier.tell() # On mesure la position du pointeur de lecture octet = fichier.read(1) # On lit un octet dans le flux if octet: print(f"Position dans le fichier {position}. Lecture : ", octet) # Affichage en affichant les valeurs décimales fichier.seek(0) octet = b'0' while octet: position = fichier.tell() # On mesure la position du pointeur de lecture octet = fichier.read(1) if octet: print(f"Position dans le fichier {position}. Lecture : ", octet[0]) # Affichage en affichant les valeurs hexadécimales fichier.seek(0) octet = b'0' while octet: position = fichier.tell() # On mesure la position du pointeur de lecture octet = fichier.read(1) if octet: print(f"Position dans le fichier {position}. Lecture : ", hex(octet[0])) # Fermeture du fichier fichier.close()

19° Utiliser le nouveau programme. Vous devriez cette fois obtenir trois fois le contenu du fichier.

Position dans le fichier 0. Lecture : b'D' Position dans le fichier 1. Lecture : b'e' Position dans le fichier 2. Lecture : b'r' Position dans le fichier 3. Lecture : b'n' Position dans le fichier 4. Lecture : b'i' Position dans le fichier 5. Lecture : b'\xe8' Position dans le fichier 6. Lecture : b'r' Position dans le fichier 7. Lecture : b'e' Position dans le fichier 8. Lecture : b' ' Position dans le fichier 9. Lecture : b'p' Position dans le fichier 10. Lecture : b'a' Position dans le fichier 11. Lecture : b'r' Position dans le fichier 12. Lecture : b't' Position dans le fichier 13. Lecture : b'i' Position dans le fichier 14. Lecture : b'e' Position dans le fichier 15. Lecture : b'.' Position dans le fichier 16. Lecture : b'\n'
Position dans le fichier 0. Lecture : 68 Position dans le fichier 1. Lecture : 101 Position dans le fichier 2. Lecture : 114 Position dans le fichier 3. Lecture : 110 Position dans le fichier 4. Lecture : 105 Position dans le fichier 5. Lecture : 232 Position dans le fichier 6. Lecture : 114 Position dans le fichier 7. Lecture : 101 Position dans le fichier 8. Lecture : 32 Position dans le fichier 9. Lecture : 112 Position dans le fichier 10. Lecture : 97 Position dans le fichier 11. Lecture : 114 Position dans le fichier 12. Lecture : 116 Position dans le fichier 13. Lecture : 105 Position dans le fichier 14. Lecture : 101 Position dans le fichier 15. Lecture : 46 Position dans le fichier 16. Lecture : 10
Position dans le fichier 0. Lecture : 0x44 Position dans le fichier 1. Lecture : 0x65 Position dans le fichier 2. Lecture : 0x72 Position dans le fichier 3. Lecture : 0x6e Position dans le fichier 4. Lecture : 0x69 Position dans le fichier 5. Lecture : 0xe8 Position dans le fichier 6. Lecture : 0x72 Position dans le fichier 7. Lecture : 0x65 Position dans le fichier 8. Lecture : 0x20 Position dans le fichier 9. Lecture : 0x70 Position dans le fichier 10. Lecture : 0x61 Position dans le fichier 11. Lecture : 0x72 Position dans le fichier 12. Lecture : 0x74 Position dans le fichier 13. Lecture : 0x69 Position dans le fichier 14. Lecture : 0x65 Position dans le fichier 15. Lecture : 0x2e Position dans le fichier 16. Lecture : 0xa

Regardons maintenant la différence entre un fichier encodant un texte en utilisant un table 1 octet et un fichier encodant un texte en UFT-8.

20° Utiliser ce nouveau programme. Changer ensuite l'encodage initial pour de l'utf-8. Pourquoi le fichier en UTF-8 prend-t-il plus de place en mémoire ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# Création et fermeture du fichier fichier = open('lecture.txt', 'w', encoding="iso8859_15") fichier.write("Dernière partie.\n") fichier.close() # Ouverture du fichier en mode byte fichier = open('lecture.txt', 'br') # Affichage en affichant les valeurs décimales octet = b'0' while octet: position = fichier.tell() # On mesure la position du pointeur de lecture octet = fichier.read(1) if octet: print(octet[0], end=" ") # Fermeture du fichier fichier.close()

...CORRECTION...

Avec la table sur un octet "iso8859_15" :

68 101 114 110 105 232 114 101 32 112 97 114 116 105 101 46 10

Avec la table sur un octet "utf-8" :

68 101 114 110 105 195 168 114 101 32 112 97 114 116 105 101 46 10

On a donc 17 octets contre 18 octets en UTF-8.

L'augmentation de taille vient des caractères non-ASCII (ici le é) qui en UTF-8 occupent 2, 3 ou 4 octets pour les plus rares.

Un fichier n'est donc qu'une suite d'octets.

Fichier texte : suite d'octets.

Fichier image : suite d'octets.

Fichier exécutable : suite d'octets.

Dernier point : cette partie n'était destinée qu'à vous montrer le principe des fichiers. Pour les fichiers-texte, la lecture ligne par ligne est facilité par l'utilisation de la méthode readline associée à une boucle FOR. C'est bien cela qu'il faut savoir utiliser.

1 2 3 4 5 6 7 8 9 10
# 1 - Création de l'objet-fichier : ouverture en mode w obj_fichier = open('aaa.txt', 'r', encoding="utf-8") print(type(obj_fichier)) # 2 - Remplissage progressif du fichier for ligne in obj_fichier: print(ligne, end="") # 3 - Fermeture de l'objet-fichier obj_fichier.close()

Si vous comprenez maintenant sans problème le code précédent, vous avez acquis ce qu'il faut sur le thème.

6 - FAQ

Expressions régulières - hors programme

Cette partie n'est pas du tout au programme. Ca va allez vite. Non pas car c'est simple mais parce qu'il y a trop à dire !.

Les expressions régulières sont un moyen de trouver des motifs dans un string.

Il faut fournir entre crochets l'ensemble des caractères qu'on recherche.

  •  [0-9]  veut dire qu'on attend un caractère numérique (0-1-2-3-4-5-6-7-8-9) et un seul.
  •  [0-9]{2}  veut dire qu'on s'attend à trouver deux chiffres : 08, 75 ou 42 sont valides mais pas 7A.
  •  ([0-9]{2}-)  signale avec les parenthèses la recherche d'une séquence composée de deux chiffres suivi d'un tiret : 78- ou 12- ou 06- mais pas Av!.

Un exemple pour la recherche d'un numéro de téléphone dans un texte. Avec Python, il faut utiliser le module re.

>>> import re >>> texte = "Le numéro de Toto l'asticot est 06-07-06-07-06..." >>> sequence = "([0-9]{2}-){4}([0-9]{2}){1}"

On recherche donc 4 séquences chiffre chiffre tiret suivi d'une unique séquence chiffre chiffre.

>>> re.search(sequence, texte) <re.Match object; span=(32, 43), match='06-07-06-07'> >>> if re.search(sequence, texte): print('Ce texte contient un n°') Ce texte contient un n° >>> trouve = re.search(sequence, texte) >>> trouve.group() '06-07-06-07-06'

On notera que la réponse de la méthode search est un objet complexe de classe Match qui contient notamment les index du début et de la fin du motif trouvé.

On peut accéder au(x) string(s) trouvé(s) en utilisant la méthode group sur cet objet.

Dernière chose : la validation des entrées. Il ne sert à rien d'enregistrer des données sans être certain de ce qu'à rentrer l'utilisateur. Si on vous demande une date et qu'on stocke 28 juin 1995, nous allons être bien géné lorsqu'il faudra traiter les données si on voulait 06-1995.

A titre d'exemple voici comment tenter de créer un test sur la date pour ne pas enregistrer la demande si la date ne respecte pas ce format :

  • une séquence de 2 chiffres suivi d'un tiret ([0-9]{2}-){1},
  • puis une séquence de 4 chiffres ([0-9]{4}){1}.
>>> sequence = "([0-9]{2}-){1}([0-9]{4}){1}"

J'ai vu plein de programmes sur le net où on ne donne pas l'encodage.

Si on ne note pas d'encodage, l'interpréteur va le choisir pour vous !

Les versions actuelles de Python sont définies avec utf-8 comme encodage par défaut.

Noter l'encodage ne fait jamais de mal, surtout quand on débute. Cela vous permet de vous souvenir qu'on a juste des octets auxquels on donne un sens en utilisant une technique d'encodage.

J'ai vu des programmes avant des with. C'est quoi ?

Le problème du fichier ? Il faut l'ouvrir et penser à le fermer. Or, parfois, une interruption du programme peut empêcher d'atteindre l'instruction de fermeture.

Dans ce cas, il arrive parfois qu'on ne parvienne plus à ouvrir le fichier car le système pense qu'il est encore ouvert. Ou alors une modification n'a pas pu être faite correctement et le fichier est corrompu (c'est à dire qu'on ne parvient plus à décoder son contenu correctement).

Pour contourner le problème, Python propose un gestionnaire de contexte, context manager en anglais. Et son utilisation se fait en utilisant le mot-clé with.

Le principe est simple : en l'utilisant à l'ouverture, l'interpréteur s'arrange pour fermer le fichier dans tous les cas. Ce n'est pas vous qui avez à placer votre méthode close. Il s'en charge tout seul.

Voici un exemple d'utilisation :

1 2
with open('lecture.txt', 'w', encoding="utf-8") as fichier: fichier.write("Dernière partie.\n")

On voit donc qu'on utilise pas d'affectation directe. On utilise les mots-clé with et as pour faire le lien entre la variable fichier et l'instruction qui a permi de la créer open('lecture.txt', 'w', encoding="utf-8").

On retrouve le : et l'indentation. Dès qu'on sort de l'indentation, c'est qu'on ferme le fichier, automatiquement. C'est l'interpréteur qui s'en charge.

Autre exemple, en lecture :

1 2 3 4 5 6
with open('lecture.txt', 'br') as fichier: octet = b'0' while octet: octet = fichier.read(1) if octet: print(octet[0], end=" ")

Activité publiée le 24 06 2020
Dernière modification : 27 03 2021
Auteur : ows. h.