Garder la mémoire

Les amis !

Image par Tobias Dahlberg de Pixabay

Vous avez réussi à faire une liste de dictionnaires pour conserver le contact. Même si votre programme est très satisfaisant, il possède un défaut majeur. Quand vous quittez le programme, l'ensemble de vos contacts disparait avec la mémoire du programme. Les données étaient stockées dans la RAM de l'ordinateur et à la fin de l'exécution du programme, cet espace est libéré.

Quand bien même vous pourriez garder le programme en fonctionnement, il faudra bien un jour éteindre l'ordinateur

Il faut faire passer ces données de la RAM,qui est une mémoire volatile, vers une mémoire à plus long terme. Le système de fichier du disque dur est tout à fait adapté pour cela.

Mécanisme de base pour écrire dans des fichiers

Python fournit un mécanisme de base d'entrée sortie pour accéder aux fichiers. Nous allons voir quelques fonctions simples, avec leurs paramètres qui nous permettront de lire et d'écrire dans un fichier

L'ouverture du fichier

La première chose à faire est d'ouvrir le fichier auquel on veut accéder. Cette ouverture se fait simplement grâce à la fonction open qui prend deux paramètres

fichier = open(filename,mode)

Le premier paramétre est le nom du fichier que l'on veut ouvrir. Le second paramètre est le mode d'ouverture. En effet, on peut ouvrir le fichier de différente façon

Mode Signification
type d'ouverture 'r' (abbréviation de read) Ouverture du fichier en lecture. On ne peut que le lire, pas écrire dedans. C'est le mode par défaut si le paramètre de mode n'est pas précisé
'w' (abbréviation de write). Si le fichier n'existe pas, il est créé. Sinon, il est ouvert en écriture et son contenu actuel est supprimé.
'a' (abbréviation de append). Ouvre le fichier en écriture, comme le mode 'w', mais au lieu de supprimer le contenu existant, le nouveau contenu sera ajouté à la fin du contenu existant
'x' (abbréviation de exclusive. Fonctionne comme 'w' mais en mode de création exclusive. Ce mode provoquera une erreur si le fichier existe déjà.
type de fichier 't' Fichier de type texte. C'est le mode par défaut si rien n'est indiqué.
'b' Fichier binaire, c'est à dire qui peut contenir des données arbitraires (des images, du son, etc). Les données sont considéres comme des bytes, sans décodage.

si par exemple on veut ouvrir en écriture un carnet d'adresse pour l'enregistrer, que le nom du fichier est contacts.txt , la commande a éxécuter sera la suivante :

fichier = open("contacts.txt",'wt')

Si après on veut relire le fichier pour importer son contenu, il suffira d'utiliser :

fichier = open("contacts.txt")

Comme on a pas indiqué de mode, on a le mode par défaut, c'est à dire 'rt' (lecture d'un fichier texte).

À faire vous même
  1. On a un fichier où l'on consigne des informations journalisées (des logs), c'est à dire des évènements qui arrivent dans un programme (par exemple telle personne a accédé à telle ressource, telle personne s'est identifiée..). On veut ouvrir le fichier prog.log pour rajouter des lignes de texte d'information dedans. Quelle commande doit on utiliser ?
  2. On veut ouvrir un fichier d'image pour le transformer. Quelle commande permet d'ouvrir le fichier perroquet.jpg pour le lire ?
  1. On en doit pas supprimer les anciens logs mais en ajouter de nouveau. On doit donc ouvrir en mode append. C'est du texte qui est utilisé. On peut mettre le t ou pas (puisque c'est le paramètre par défaut)
    fichier = open("prog.log",'a')
  2. Une image est un fichier binaire. On veut la lire. Le mode sera donc 'rb'
    fichier = open("perroquet.jpg",'rb')

Fermeture du fichier

La fonction open renvoie un objet de type fichier. On sauvegarde cet objet dans la variable fichier (qui pourrait avoir n'importe quel nom). Lorsque le fichier est ouvert, il ne va pas être accessible pour d'autres programmes. C'est pour cela que dès que l'on a fini d'utiliser le fichier, il faut bien penser à le ferme, grâce à la méthode close

fichier.close()

Écriture dans le fichier

Pour écrire dans le fichier, on utilise la méthode write surl'objet fichier. Pour tous le reste de ce document, on considérera que l'on est en mode texte. Pour écrire du texte, on va utiliser

fichier.write("Ce texte est écrit dans le fichier")

La fonction write va écrire les données les unes à la suite des autres. Si on veut aller à la ligne dans le fichier, il faut penser à rajouter le caractère de fin de ligne (\n) dans la chaine de caractère que l'on veut utiliser. On va utiliser le programme suivant pour écrire le début de notre fichier

fruits = ['orange','ananas','kiwi','abricot']
fichier = open("fruits.txt",'w')
for fruit in fruits:
    fichier.write(fruit+'\n')
fichier.close()
print("Le fichier est enregistré")
À faire vous même

Vous allez utiliser le code ci dessus pour créer un fichier contenant votre liste de fruits. Vous téléchargerez votre fichier etvous vérifirez son contenu dans un éditeur de texte quelconque.

Lire dans le fichier

Il y a trois façons de lire dans un fichier. Chacune correspond à un usage différent.

La méthode read : cette méthode lit la totalité du fichier d'un seul coup et va renvoyer l'ensemble sous forme d'une unique chaine texte.

fichier = open("fruits.txt")
contenu = fichier.read()
# la variable contenu vaut pour notre exemple "orange\nananas\nkiwi\nabricot\n"
fichier.close()
print(contenu)

La méthode readlines : cette méthode var lire elle aussi la totalité du fichier, mais elle va renvoyer le résultat sous forme d'un tableau, chaque case du tableau contenant une ligne du fichier. On peut donc après effectuer une boucle for sur le tableau qui agira sur chaque ligne du fichier.

fichier = open("fruits.txt")
lignes = fichier.readlines()
# la variable lignes vaut pour notre exemple ['orange\n','ananas\n','kiwi\n','abricot\n']
fichier.close()
for element in lignes:
    element = element.rstrip("\n") #on enlève le saut de ligne à la fin
    if element =="kiwi":
        print("j'adore le kiwi")
    else:
        print(f"J'aime bien l'{element} mais je préfère le kiwi !")

La dernière méthode est readline (sans le s). Cette méthode est surtout utilisée lorsque le fichier est un fichier de grande taille et que l'on ne veut pas charger l'intégralité d'un fichier en mémoire d'un seul coup. Par exemple, les journaux qui représentent les accès à un serveur web peuvent facilement représenter plusieurs Go de données. Charger le fichier en mémoire d'un seul coup prendrait plusieurs Go d'espace dans la mémoire vive, ce qui n'est pas souhaitable. On utilise la méthode readline au sein d'une boucle while. En effet, à la fin du fichier, readline renvoie une chaine vide (alors qu'une ligne vide renvoie "\n")

fichier = open("fruits.txt")
# on lit ligne par ligne
ligne = fichier.readline()
while ligne !="":
    ligne = ligne.rstrip("\n") # on enlève le saut de ligne à la fin
    if ligne =="kiwi":
        print("j'adore le kiwi")
    else:
        print(f"J'aime bien l'{ligne} mais je préfère le kiwi !")
    ligne = fichier.readline() # lecture de la ligne suivante
# on ne ferme qu'après avoir tout lu
fichier.close()

Lire et écrire en utilisant with

Le langage Python permet d'utiliser, pour accéder aux fichiers, un élément syntaxique qui encadre ce que l'on fait sur le fichier et se chargera de le ferme à la fin, même s'il y a un problème : with.

l'expression with encadre un bloc qui contient tout ce qui sera fait sur la fonction. Nos exemples deviennent plus simples pour lire et écrire, et plus sécurisés

Écriture du fichier

fruits = ['orange','ananas','kiwi','abricot']
with open("fruits.txt",'w') as fichier :
    for fruit in fruits:
        fichier.write(fruit+'\n')

print("Le fichier est enregistré")

On voit que l'on a pas eu à gérer la fermeture du fichier.

Lecture du fichier

On peut bien entendu utiliser la même syntaxe pour accéder aux fichiers avec with afin de les lire (avec read et readlines) en une fois.

Très souvent, on préfère lire les fichiers ligne par ligne, cela fonctionnant aussi avec les gros fichiers. On peut alors utiliser une boucle for ce qui allégera la syntaxe. En utilisant

for ligne in fichier:

On aura accés à chaque ligne du fichier successivement

Le dernier exemple ci dessous va d'abord ouvrir le fichier pour écrire dedans, le fermer, puis l'ouvrir en lecture pour le lire ligne à ligne

fruits = ['orange','ananas','kiwi','abricot']
with open("fruits.txt",'w') as fichier :
    for fruit in fruits:
        fichier.write(fruit+'\n')

print("Le fichier est enregistré")

with open("fruits.txt") as fichier:
    for ligne in fichier:
        ligne = ligne.rstrip("\n")
        print(f" nouveau fruit: {ligne}")

print("le fichier a été lu et affiché")

En résumé ...

Relisez les paragraphes ci dessus et faites une fiche de résumé qui montre un programme qui fait toutes les actions suivantes :

À retenir
  • Ouverture d'un fichier
  • Indiquer les différents modes d'ouverture
  • Écriture dans un fichier
  • Lecture dans un fichier (read,readlines et readline)
  • Utilisation de with

Mini projet d'annuaire de contacts

Maintenant que nous savons écrire dans un fichier, nous allons pouvoir créer notre fichier de contact. Ce qui est dans la mémoire de l'ordinateur pourra être sauvegardé. Ainsi, lorsque l'on quitte l'application, on ne perdra plus l'ensemble de nos données.

Vous allez compléter le fichier qui est donné ci après. Vous avez juste 5 fonctions à compléter. Le fonctionnement en est simple :

  • Une fonction sert pour ajouter un contact. Elle demande à l'utilisateur toutes les informations (nom, prénom, adresse mail, téléphone, adresse postale, compte instagram, compte snapchat, surnom) et renvoi toutes ces informations sous forme d'un dictionnaire (qui pourra être ajouté à la liste des contacts)
  • Une fonction affiche tous les contacts. Elle affiche leur numéro dans la liste et peut être une partie seulement des informations (par exemple nom, prénom et téléphone)
  • Une fonction permet de visualiser le détail d'un contact
  • Une fonction permet de supprimer un contact
  • Enfin, une fonction permet de sauvegarder l'ensemble du carnet d'adresse. Voici le fonctionnement attendu :
    1. pour chaque contact, elle commence par indiquer le numéro du contact encadré par des tirets (par exemple : ----- contact n° 17 -----)
    2. Pour chaque entrée du dictionnaire correspondant au contact, elle ajoute une ligne dans le fichier avec la clef suivie de : et de la valeur associée (par exemple nom : Durand)

Tant que le programme tourne, il vous propose un choix : ajouter, lister, détail, suppression ou quitter. Au moment de quitter, il sauvegarde les contacts dans un fichier dont vous choisissez le nom.

PS : vous pouvez vous servir du code que vous avez réalisé pour le chapitre précédent, qui gérait les dictionnaires de contact

PPS : vous pouvez travaillez dans le navigateur ou utiliser un IDE comme visual studio code si vous préférez. Si vous travaillez dans le navigateur, pensez à sauvegarder régulièrement votre travail en téléchargeant le script

Et le chargement ?

Vous avez peut être remarqué : à la fin de notre programme nous sauvegardons la liste de contacts. Nous ne perdons plus la mémoire. La liste de contact est sauvegardée dans un fichier que vous pouvez lire (à la fin de l'activité, vous avez pu créer votre fichier et le sauvegarder sur votre ordinateur)

Mais nous n'avons pas prévu d'importer notre fichier de contacts dans notre programme. C'est dommage, ce serait une fonctionnalité très intéressante. Oui, mais voilà, la façon dont nous avons enregistré les contacts ne s'y prête pas trop. Il faudrait parcourir le fichier ligne par ligne et recréer chaque dictionnaire.

C'est possible. Mais ce n'est pas le plus pratique, de très loin.

Nous allons voir qu'il existe une autre façon d'enregistrer les fichiers dans le chapitre suivant.