python fichier

Identification

Infoforall

27 - Enregister et lire des fichiers


Vous savez maintenant qu'il existe plusieurs encodages possibles pour les caractères. Nous avons fait des activités sur les stuctures de données et sur le format CSV. Mais comment enregistre-t-on des données ? Comment enregistrer un dictionnaire par exemple...

Prérequis : Python - Encodage des textes.

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° Enregistrer ce script dans un répertoire qu'on nommera activiteFichier.

📁 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()

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.

📁 activiteFichier

📄 script_test.py

📄 aaa.txt

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 : on écrit des octets dans le fichier. Si on ne signale pas qu'il faut insérer l'octet signalant le passage à la ligne, on ne le rajoute pas automatiquement !

Comme vous avez dû le voir, 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.

Tentons avec cette méthode.

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. Qu'est-ce qui est surprenant ?

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()

...CORRECTION...

Voici le contenu :

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

La chose surprenante : le nouveau contenu a supprimé le premier contenu !

Alors comment faire pour rajouter du contenu et non pas le supprimer à chaque fois qu'on ouvre le fichier à nouveau ?

Tout vient de l'argument qu'on fournit en plus du nom du fichier.

Créer ou rajouter du texte dans un fichier-texte

Pour écrire dans un fichier-texte, il faut commencer par l'ouvrir avec la fonction-constructeur 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.

Etape 1 (option w) - Ouverture en mode w comme "write"

1
obj_fichier = open('aaa.txt', 'w', encoding="utf-8")

Cela crée l'objet-fichier obj_fichier mais supprime l'ancien contenu si le fichier existe déjà.

Etape 1 (option a) - Ouverture en mode a comme "append"

1
obj_fichier = open('aaa.txt', 'a', encoding="utf-8")

Cela crée l'objet-fichier obj_fichier mais sans effacer le contenu.

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

Etape 2 - Rajout de contenu avec la méthode write

On utilise la notation nom_du_fichier suivi d'un point suivi du nom_de_la_méthode à_utiliser.

Attention, si vous voulez rajouter un passage à la ligne, ce n'est pas automatique : il faudra l'indiquer à l'aide de la présence de  \n  dans la chaîne.

2
obj_fichier.write("Voici une nouvelle ligne\n")

Etape 3 - Fermeture du fichier avec close

Si la fermeturer est mal effectuée, ou pas effectuée, cela peut entrainer des problèmes lors d'une prochaine ouverture.

3
obj_fichier.close()

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.

Saut à la ligne avec Windows

La lecture d'un fichier-texte issu de Windows montre parfois la présence d'un autre caractère particulier en plus de  \n  : le caractère d'échappement retour-chariot  \r . Il faudra donc les supprimer éventuellement.

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.

1 / 5 - Lecture manuelle d'une ligne

05° Utiliser le script suivant : il va vous permettre de lire et afficher les 4 lignes du fichier : la méthode readline() va transmettre le flux de la position actuelle de la tête de lecture (le début du fichier au départ) jusqu'à rencontrer un passage à la ligne  \n .

Ici, chaque ligne sera simplement affichée sur la console à l'aide de la fonction native print.

1 2 3 4 5 6 7 8 9 10 11
# 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 print(obj_fichier.readline(), end="") print(obj_fichier.readline(), end="") print(obj_fichier.readline(), end="") print(obj_fichier.readline(), end="") # 3 - Fermeture de l'objet-fichier obj_fichier.close()

Exécuter ce script vous permettra d'obtenir ceci dans la Console :

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.

Que fait la méthode readline ? Elle va fournir la chaîne de caractères qu'on lit dans le fichier entre la position actuelle et le prochain LINE FEED  \n  rencontré.

Avec cette façon de faire, si on a 1500 lignes, on est parti pour taper 1500 fois print... Heureusement, notre objet-fichier obj_fichier est un itérable : on peut utiliser une boucle FOR.

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

2 / 5 - Utilisation d'une boucle non bornée

On va demander de lire tant que la méthode renvoie bien quelque chose.

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

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

  • Quelle est la condition qui permet de continuer à boucler ?
  • A quoi sert la ligne 5 ?

...CORRECTION...

On demande à boucle tant que la lecture du fichier fournit bien une chaîne de caractères non vide.

La ligne 5 permet simplement de créer une première fausse chaîne de caractères. Le tout est qu'elle soit non vide.

07° Tester cette nouvelle version : quelle est la seule différence ?

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()

...CORRECTION...

Le test pour continuer est beaucoup plus simple si on sait le lire.

Il veut 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...

Tester un contenu

Cela ne nous avez pas servi plus que cela jusqu'à présent. Mais en Python, on peut créer une condition booléenne ne contenant qu'un contenu.

L'interpréteur Python va alors convertir ce contenu en True ou False.

Comment ?

En gros, tout ce qui n'est pas ni 0, ni vide, ni None est traduit en True.

Quelques exemples où on utilise un SI dont la condition n'est composée que d'une variable :

>>> a = None >>> if a: print("Test positif") >>> a = 0 >>> if a: print("Test positif") >>> a = 1 >>> if a: print("Test positif") Test positif
>>> a = "" >>> if a: print("Test positif") >>> a = "z" >>> if a: print("Test positif") Test positif
>>> a = [] >>> if a: print("Test positif") >>> a = [15] >>> if a: print("Test positif") Test positif
>>> a = () >>> if a: print("Test positif") >>> a = (15) >>> if a: print("Test positif") Test positif
>>> a = {} >>> if a: print("Test positif") >>> a = {'cle':15} >>> if a: print("Test positif") Test positif

Il faut juste faire attention aux cas un peu tordu comme celui-ci par exemple :

>>> a = [] >>> if a: print("Test positif") >>> a = None >>> if a: print("Test positif") >>> a = [None] >>> if a: print("Test positif") Test positif

3 / 5 - Lecture ligne par ligne avec une boucle bornée POUR

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

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).

4 / 5 - Lecture d'un caractère à la fois

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. On fournira 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.

09° Ci-dessous 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="*")

Utiliser le script pour visualiser le résultat.

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()

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. **

5 / 5 - Encodage

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éer 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° Lire et utiliser le script suivant qui crée un fichier en UTF-8 puis qui le lit en UFT-8.

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()

Question

Modifier le fichier pour le créer en UTF-8 mais en le lisant 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.

Ci-dessous le script initial et le résultat attendu avant et après modification.

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.

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

C'est écrit en UTF-8 ? De toutes maniÚres, j'ai jamais compris à vos histoires d'encodage.

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 texte du fichier-texte est de 279 octets.

Ouvrir le fichier en cliquant dessous pour vérifier qu'il contient bien le bon texte.

✎ 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 - Actions sur les 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 : actions et tests sur les strings

Revoyons quelques actions assez pratiques.

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

Tester si un string contient toto ?

Pratique aussi pour savoir si un mot-clé apparaît bien dans une séquence.

>>> nom = "Merlin ou toto l'asticot" >>> 'toto' in nom True >>> 'grand magicien' in nom False

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"
>>> nom = "Merlin ou Toto l'asticot" >>> 'TOTO' in nom False >>> 'TOTO' in nom.upper() True >>> nom "Merlin ou Toto l'asticot"

Si vous voulez voir les autres méthodes, vous pouvez aller voir cette fiche ou faire des recherches sur le Web :

FICHE STRINGS

✎ 13° Expliquer ce que fait ce programme étape par étape.

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.

Qu'aurions-nous pu mettre à la place de "o" en ligne 3 ?

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()

✎ 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 autre programme, capable de lire ligne par ligne les enregistrements dans le fichier que nous venons de créer.

Si vous avez du courage, vous pouvez aller jusqu'à créer un affichage plus joli en récupérant les différents attributs en utilisant la méthode split qui divise le string en utilisant un caractère séparateur et renvoie un tableau.

>>> entree = "aaa;bbb;ccc;ddd" >>> champs = entree.split(";") >>> champs ['aaa', 'bbb', 'ccc', 'ddd'] >>> champs[0] 'aaa'
Expressions régulières - hors programme

Cette partie va aller 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 "petite" 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.

✎ 16° 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, puis une séquence de 4 chiffres.

>>> sequence = "([0-9]{2}-){1}([0-9]{4}){1}"

5 - 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.

17° 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()

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

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=" ")

Si nous savons créer des formulaires HTML, si nous savons récupérer les requêtes associées sur un serveur et enregistrer les résultats dans un fichier, nous allons être capables de créer une vraie première application Web assez complexe. C'est le but de la prochaine activité sur le thème du Web.

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