Chapitre 5.1 - Manipulation de fichiers⚓︎
1. Lire un fichier⚓︎
Le Projet Gutenberg est une bibliothèque en ligne regroupant les versions numériques d'ouvrages libres de droits. On y a récupéré le fichier des Fables de la Fontaine au format txt
.
1.1 La fonction open
⚓︎
Ouvrir un fichier avec Python est simple. On utilise la fonction open
présente dans la bibliothèque native.
Cette fonction prend plusieurs paramètres. Retenons les trois suivants (déroulez pour avoir des détails):
file
: le nom du fichier
Le nom du fichier (avec son extension donc, au format str
).
Attention, par « nom » on désigne l'adresse du fichier. Cette adresse peut-être :
-
absolue, depuis la racine du disque,
C:/home/nico/Documents/donnees_en_table/fables.txt
par exemple ; -
ou relative, depuis le fichier Python qui ouvre le fichier,
fables.txt
par exemple si les deux fichiers sont dans le même dossier.
On conseille très fortement d'utiliser des adresses relatives.
mode
: le mode d'ouverture
Le mode d'ouverture du fichier (au format str
).
On peut retenir les modes suivants :
Caractère | Signification |
---|---|
'r' |
ouvre en lecture, en mode texte |
'w' |
ouvre en écriture, en effaçant le contenu du fichier |
'a' |
ouvre en écriture, en ajoutant les données à la fin du fichier |
'b' |
mode binaire |
On notera que le mode 'w'
efface directement le contenu du fichier, il n'y a pas de message d'avertissement !
encoding
: l'encodage utilisé
Le type d'encodage (au format str
).
L'encodage d'un fichier correspond à la façon dont le programme qui l'ouvre doit interpréter les données qu'il contient.
Un fichier est stocké en machine sous forme d'une succession de bits. Dans la table ASCII initiale, 7 bits représentent un caractère. Dans la table ASCII étendue, il faut 8 bits pour représenter un caractère. L'encodage 'utf-8'
est plus subtil : les caractères « courants » (l'alphabet latin par exemple) sont codés sur 8 bits, les caractères moins « courants » sur 16 voire 24 bits.
Changer l'encodage lors de l'ouverture d'un fichier ne modifie pas les données contenues dans le fichier mais la façon de les lire.
Par exemple les bits 010100110110100101101101011100000110110001100101001000000111010001100101011110000111010001100101
lus :
-
avec l'encodage
'utf-8'
donnent'Simple texte'
, -
avec l'encodage
'utf-16 LE'
donnent'楓灭敬琠硥整'
!
L'encodage le plus classique pour nous sera 'utf-8'
.
La fonction open
peut être utilisée de deux façons :
-
utilisation classique, on ouvre et on ferme le fichier :
Pythonfichier = open(file="fichier.txt", mode="r", encoding="utf-8") # Traitement du fichier fichier.close()
Techniquement, on devrait même utiliser un
try ... except
au cas où le fichier est inaccessible : -
utilisation avec
with
, il est inutile de fermer le fichier et de gérer les erreurs, c'est automatique :
On utilisera la seconde méthode.
1.2 Lire le fichier, des lignes, une ligne !⚓︎
Une fois le fichier ouvert, on peut réaliser différentes actions. Si l'objet renvoyé par open
s'appelle fichier
, on peut :
fichier.read()
: lit la totalité du fichier. Renvoie une unique chaîne de caractères.fichier.readlines()
: lit la totalité du fichier ligne par ligne. Renvoie la liste contenant les différentes lignes.fichier.readline()
: lit la prochaine ligne du fichier ligne par ligne. Renvoie une chaîne de caractères.
Écrire ?
Si le fichier est ouvert en mode écriture, on peut écrire en faisant fichier.write("texte à écrire")
.
Attention toutefois à ne pas écraser le contenu du fichier !
Les deux scripts ci-dessous sont donc équivalents :
with open(file="fichier.txt", mode="r", encoding="utf-8") as fichier:
contenu = fichier.readlines()
contenu = []
with open(file="fichier.txt", mode="r", encoding="utf-8") as fichier:
for ligne in fichier:
contenu.append(ligne)
La seconde permet toutefois de traiter précisément chaque ligne lue. On l'utilisera préférentiellement.
1.3 Des cigales et des fourmis⚓︎
Nous sommes donc équipés pour ouvrir et lire nos fichiers.
Lire les fables de la Fontaine
Le fichier contenant les fables de la Fontaine est nommé fables.txt
, il est situé dans le même dossier que le fichier Python manipulé par l'éditeur. Il est encodé en utf-8
.
Compléter le script afin d'ouvrir ce fichier et charger ses différentes lignes dans une liste.
On obtient la liste suivante :
fables = [
'FABLES DE LA FONTAINE\n',
'\n',
'I\n',
'\n',
'LA CIGALE ET LA FOURMI.\n',
'\n',
'\n',
'La cigale, ayant chanté\n',
"Tout l'été,\n",
...
]
Le '\n'
que l'on observe à plusieurs reprises est le caractère de retour à la ligne. On peut le supprimer en faisant ligne.strip()
. En effet, la méthode strip
supprime les caractères « blancs » au début ou à la fin d'une chaîne de caractères.
La lecture du fichier devient alors :
fables = []
with open(file="fables.txt", mode="r", encoding="utf-8") as fichier:
for ligne in fichier:
ligne_propre = ligne.strip() # suppression des \n
fables.append(ligne_propre)
On obtient :
fables = [
'FABLES DE LA FONTAINE',
'',
'I',
'',
'LA CIGALE ET LA FOURMI.',
'',
'',
'La cigale, ayant chanté',
"Tout l'été,",
...
]
Relire les fables de la Fontaine
On a supprimé les caractères de retour à la ligne mais il reste désormais des lignes vides dans la liste fables
.
Compléter le script afin d'ouvrir ce fichier, charger ses différentes lignes non vides dans une liste.
# Tests
(insensible à la casse)(Ctrl+I)
1.4 Comptons les moutons⚓︎
Nous avons donc récupéré l'ensembles des fables dans une liste contenant toutes les lignes. Nous pouvons désormais faire des requêtes sur cette liste.
Combien de vers contiennent le mot "mouton"
? Pour le savoir on fait :
moutons = [vers for vers in fables if "mouton" in vers.lower()] # tous les vers contenant "mouton"
print(len(moutons)) # le nombre de vers
Astuce
On passe le vers en minuscule avec vers.lower()
afin de trouver en une seule passe les chaînes "mouton"
, "Mouton"
, "MOUTON"
, etc
Requêtes dans les fables
Compléter le script ci-dessous afin d'effectuer les requêtes demandées.
Toutes les recherches de chaînes de caractères seront insensibles à la casse (utiliser vers.lower()
comme ci-dessus).
# Tests
(insensible à la casse)(Ctrl+I)
ENCRYPTION_TOKEN
Solution
ENCRYPTION_TOKEN
Les fichiers CSV (pour Comma Separated Values) sont des fichiers-texte (ils ne contiennent aucune mise en forme) utilisés pour stocker des données, séparées par des virgules (ou des points-virgules, ou des espaces...). Il n'y a pas de norme officielle du CSV.
2. Les fichiers csv
et json
⚓︎
2.1 Découverte⚓︎
Le site data.gouv propose de nombreux jeux de données en libre accès.
Les fichiers correspondants sont souvent proposés aux formats
csv
pour Comma Separated Values,json
pour JavaScript Object Notation.
Ces deux formats de fichiers permettent de présenter des données textuelles. Voici par exemple les mêmes informations présentées dans chacun des formats :
-
au format
csv
(le fichier s'appelleamis.csv
): -
au format
json
(le fichier s'appelleamis.json
):
Nous travaillerons désormais avec les fichiers csv
. L'exemple précédent permet de remarquer plusieurs choses :
-
un fichier
csv
contient des données textuelles, -
les données sont organisées en lignes,
-
la première ligne regroupe le nom des descripteurs (il y en a quatre ici :
nom
,âge
,ville
etpassion
), -
les autres lignes contiennent des enregistrements (il y en a deux ici :
Jean,26,Paris,VTT
etMarion,28,Lyon,badminton
), -
au sein de chaque ligne, les valeurs sont délimitées par un séparateur (ici le caractère
","
), -
les données peuvent être de types différents. Ici le
nom
, laville
et lapassion
sont des chaînes de caractères, l'âge
un entier.
Attention
La réalité n'est pas aussi simple :
-
il arrive que la première ligne ne contienne pas les entêtes. Ils peuvent être listés dans un fichier annexe ou... perdus !
-
on trouve parfois une seconde ligne contenant les types des données (entier, texte...).
-
le séparateur n'est pas toujours une virgule. Il est courant que l'on trouve des
";"
dans les fichiers français car la virgule est utilisée comme séparateur décimal.
Premiers contacts
On considère les deux fichiers csv
ci-dessous (on n'en donne que les trois première lignes) :
petanque.csv
(Localisation des terrains de pétanque dans l'agglomération de Tours) :
geo_point_2d;nb_equipement;commune;cp
(47.3392380011,0.7162219998);1;Chambray-lès-Tours;37170
(47.3300100011,0.6120900019);5;Ballan-Miré;37510
bac.csv
(Résultats au baccalauréat par académie) :
session,academie,sexe,diplome_specialite,nombre_d_inscrits,nombre_d_admis_totaux
INT,TEXT,TEXT,TEXT,INT,INT
2021,AIX-MARSEILLE,FILLES,BAC PRO AG 21302 GEST MILIEUX NATURELS FAUNE,16,13
Cochez la ou les bonnes réponses.
- Le séparateur du fichier
petanque.csv
est la virgule - Le fichier
petanque.csv
compte quatre descripteurs - Le séparateur du fichier
bac.csv
est la virgule -
INT
est un descripteur du fichierbac.csv
- Le séparateur du fichier
petanque.csv
est le point-virgule - Le fichier
petanque.csv
compte bien quatre descripteurs - Le séparateur du fichier
bac.csv
est bien la virgule -
INT
est un type de données
Problème !
On propose ci-dessous un extrait d'un fichier csv
. Identifiez les trois problèmes présents :
nom,prenom,identifiant;mdp,derniere_connexion
Clark,Sarah,sclark,k012345,20230105,
Mapple,Marc,marc.mapple,20221231
Solution
- Le séparateur n'est pas constant : il y a un point-virgule dans la première ligne
- Il y a une virgule en trop en fin de deuxième ligne
- Il manque un champs sur la troisième ligne
On pourrait aussi noter le gros problème qui consiste à stocker les mots de passe des utilisateurs en clair dans un fichier !
Autres formats...
Les fichiers csv
et json
ne sont pas les seuls formats permettant de conserver des données.
On peut aussi retenir le format xml
pour eXtensible Markup Language qui utilise des balises au même titre que le html
:
2.2 Création⚓︎
On l'a dit, les fichiers csv
et json
sont des fichiers « texte » classique. Il est donc possible de les créer, d'ouvrir ou de modifier avec un simple éditeur de texte.
2.2.1 Ouverture/modification d'un fichier CSV par des logiciels classiques
- Télécharger le fichier exemple.csv
- Ouvrir avec le Bloc-Notes ce fichier.
- Rajouter une ligne avec une personne supplémentaire, sauvegarder le fichier.
- Ouvrir le fichier avec LibreOffice.
2.2.2 Création avec python
« Créer » un fichier csv
On souhaite « créer » un fichier csv
recensant les jours fériés en France durant l'année 2023.
Afin de rester dans l'interface proposée par ce site nous travaillerons dans un éditeur Python.
Pour de vrai !
Au lieu de travailler dans l'éditeur Python proposé ci-dessous, vous pouvez utiliser votre propre éditeur et réellement créer le fichier csv
en l'enregistrant avec l'extension .csv
. Vous pourrez ensuite le lire comme vu plus haut. Remarquez qu'un "copié/collé" de cet écran peut vous faire gagner du temps. Il faudra juste le transformer un peu ...
Ces jours sont présentés dans le tableau ci-dessous :
motif | jour | numero | mois |
---|---|---|---|
Jour de l'an | dimanche | 1 | janvier |
Lundi de Pâques | lundi | 10 | avril |
Fête du travail | lundi | 1 | mai |
Victoire 1945 | lundi | 8 | mai |
Ascension | jeudi | 18 | mai |
Fête Nationale | vendredi | 14 | juillet |
Assomption | mardi | 15 | août |
Toussaint | mercredi | 1 | novembre |
Armistice 1918 | samedi | 11 | novembre |
Noël | lundi | 25 | décembre |
Compléter la chaîne de caractère contenu
ci-dessous en saisissant le contenu du fichier csv
:
- on saisira les descripteurs sur la première ligne,
- on utilisera la virgule comme séparateur.
Vous pouvez saisir les descripteurs dans l'ordre que vous souhaitez, il faut par contre faire en sorte de saisir les valeurs dans le même ordre !
# Tests
(insensible à la casse)(Ctrl+I)
ENCRYPTION_TOKEN
Solution & Remarques
Remarques :
Comme indiqué dans l'énoncé, l'ordre des descripteurs n'a pas d'importance. Il faut simplement être cohérent :
contenu = """
numero,mois,motif,jour
1,janvier,Jour de l'an,dimanche
10,avril,Lundi de Pâques,lundi
1,mai,Fête du travail,lundi
8,mai,Victoire 1945,lundi
18,mai,Ascension,jeudi
14,juillet,Fête Nationale,vendredi
15,août,Assomption,mardi
1,novembre,Toussaint,mercredi
11,novembre,Armistice 1918,samedi
25,décembre,Noël,lundi
"""
ENCRYPTION_TOKEN
3. Exploitation d'un fichier CSV en Python⚓︎
L'utilisation d'un tableur peut être délicate lorsque le fichier CSV comporte un très grand nombre de lignes.
Python permet de lire et d'extraire des informations d'un fichier CSV même très volumineux, grâce à des modules dédiés, comme le bien-nommé csv
(utilisé ici) ou bien pandas
(qui sera vu plus tard).
3.1 Première méthode. Création d'une liste⚓︎
Le script suivant :
Python | |
---|---|
donne :
['Prénom', 'Nom', 'Email', 'SMS']
['John', 'Smith', 'john@example.com', '33123456789']
['Harry', 'Pierce', 'harry@example.com', '33111222222']
['Howard', 'Paige', 'howard@example.com', '33777888898']
Problèmes
- Les données ne sont pas structurées : la première ligne est la ligne des «descripteurs» (ou des «champs»), alors que les lignes suivantes sont les valeurs de ces descripteurs.
- La variable
donnees
n'est pas exploitable en l'état. Ce n'est pas une structure connue.
3.2 Améliorations. Créaction d'un dictionanire⚓︎
Au lieu d'utiliser la fonction csv.reader()
, utilisons csv.DictReader()
. Comme son nom l'indique, elle renverra une variable contenant des dictionnaires.
Le script suivant :
Python | |
---|---|
donne
{'Prénom': 'John', 'Nom': 'Smith', 'Email': 'john@example.com', 'SMS': '33123456789'}
{'Prénom': 'Harry', 'Nom': 'Pierce', 'Email': 'harry@example.com', 'SMS': '33111222222'}
{'Prénom': 'Howard', 'Nom': 'Paige', 'Email': 'howard@example.com', 'SMS': '33777888898'}
C'est mieux ! Les données sont maintenant des dictionnaires. Mais nous avons juste énuméré 3 dictionnaires. Comment ré-accéder au premier d'entre eux, celui de John Smith ? Essayons :
>>> donnees[0]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-3-9914ab00321e> in <module>
----> 1 donnees[0]
TypeError: 'DictReader' object does not support indexing
3.3 Une liste de dictionnaires⚓︎
Nous allons donc créer une liste de dictionnaires.
Le script suivant :
Python | |
---|---|
permet de faire ceci :
>>> amis
[{'Prénom': 'John',
'Nom': 'Smith',
'Email': 'john@example.com',
'SMS': '33123456789'},
{'Prénom': 'Harry',
'Nom': 'Pierce',
'Email': 'harry@example.com',
'SMS': '33111222222'},
{'Prénom': 'Howard',
'Nom': 'Paige',
'Email': 'howard@example.com',
'SMS': '33777888898'}]
>>> print(amis[0]['Email'])
john@example.com
>>> print(amis[2]['Nom'])
Paige
3.4 Import d'un fichier csv
dans une liste de listes⚓︎
On considère le fichier temperatures_2020.csv. Ce fichier regroupe les températures minimales, maximales et moyennes dans différentes régions françaises pour certains jours de l'année 2020. Il est dans le dossier de travail et est encodé en utf-8
.
Les premières lignes du fichier sont données ci-dessous :
mois,jour,région,tmin,tmax,tmoy
août,13,Pays de la Loire,19.25,25.35,22.3
août,13,Occitanie,17.51,26.55,22.03
Repérer les bonnes informations
Observez l'extrait proposé et répondez aux questions suivantes :
- Quel est le séparateur utilisé ?
- Combien y-a-t-il de descripteurs ?
- Quels sont les types des descripteurs ? (entier, nombre décimal, chaîne de caractères...)
Solution
- Le séparateur est la virgule
- Il y a six descripteurs
mois
etrégion
sont des chaînes de caractères,jour
est un entier, les trois autres sont des flottants.
Un fichier csv
est un fichier contenant des données textuelles : son importation avec Python peut se faire facilement avec open
.
On propose dans un premier temps d'importer les données dans une liste de listes. Voici un code fonctionnel :
Important
Prenez le temps de lire les commentaires !
Cliquez sur les +
temperatures = []
with open(file="temperatures_2020.csv", mode="r", encoding="utf-8") as fichier:
fichier.readline() # (1)
for ligne in fichier: # (2)
ligne_propre = ligne.strip() # (3)
valeurs = ligne_propre.split(",") # (4)
temperatures.append(valeurs)
- Les descripteurs ne sont pas utilisés : on lit la première ligne sans l'ajouter au résultat
- Parcours et lecture de toutes les lignes restantes
- on ôte le
\n
en fin de ligne - on découpe la ligne à chaque caractère
","
en une liste de valeurs
On obtient le résultat suivant :
temperatures = [
["août", "13", "Pays de la Loire", "19.25", "25.35", "22.3"],
["août", "13", "Occitanie", "17.51", "26.55", "22.03"],
["août", "14", "Pays de la Loire", "17.7", "25.7", "21.7"],
...
]
Les données ont bien été importées mais elles sont mal typées : les températures sont par exemple stockées sous forme des chaînes de caractères. Sous cette forme la somme "19.25" + "26.55"
renvoie "19.2526.55"
!
Il reste donc à typer les données. Par défaut celles-ci sont toutes au format str
. Seuls les nombres entiers et les décimaux sont à typer.
On rappelle les indices ci-dessous :
Descripteur | mois |
jour |
région |
tmin |
tmax |
tmoy |
---|---|---|---|---|---|---|
Indice | 0 |
1 |
2 |
3 |
4 |
5 |
Type Python | str |
int |
str |
float |
float |
float |
Il est possible de typer toutes les valeurs à l'indice 1
en faisant :
for entree in temperatures:
entree[1] = int(entree[1]) # int convertit une chaîne de caractère en un entier
Import et typage complets
Compléter le script ci-dessous permettant d'importer et de typer convenablement les données du fichier temperatures_2020.csv
.
On rappelle que float
permet de convertir une chaîne de caractère en un flottant.
# Tests
(insensible à la casse)(Ctrl+I)
ENCRYPTION_TOKEN
Solution & Remarques
Remarques :
On peut aussi typer les données dès l'importation :
temperatures = []
with open(file="temperatures_2020.csv", mode="r", encoding="utf-8") as fichier:
fichier.readline()
for ligne in fichier:
ligne_propre = ligne.strip()
valeurs = ligne_propre.split(",")
# Typage
valeurs[1] = int(valeurs[1])
for indice in [3, 4, 5]:
valeurs[indice] = float(valeurs[indice])
# Ajout de la nouvelle ligne
temperatures.append(valeurs)
ENCRYPTION_TOKEN
4. Une application : les joueurs de rugby du TOP14⚓︎
Le fichier top14.csv
contient tous les joueurs du Top14 de rugby, saison 2019-2020, avec leur date de naissance, leur poste, et leurs mensurations.
Ce fichier a été généré par Rémi Deniaud, de l'académie de Bordeaux.
Exercice 1
Stocker dans une variable joueurs
les renseignements de tous les joueurs présents dans ce fichier csv.
4.1 Première analyse⚓︎
Exercice 3
Quel est le nom du joueur n°486 ?
4.2 Extraction de données particulières⚓︎
Exercice 4
En 2019, où jouait Baptiste SERIN ?
Correction
La méthode la plus naturelle est de parcourir toute la liste jusqu'à trouver le bon joueur, puis d'afficher son équipe.
Une méthode plus efficace est d'utiliser une liste par compréhension incluant un test.
Exercice 5
Qui sont les joueurs de plus de 140 kg ?
Attention à bien convertir en entier la chaine de caractère renvoyée par la clé Poids
, à l'aide de la fonction int()
.
5. Exploitation graphique⚓︎
Nous allons utiliser le module Matplotlib pour illustrer les données de notre fichier csv.
Pour tracer un nuage de points (par l'instruction plt.plot
), Matplotlib requiert :
- une liste
X
contenant toutes les abscisses des points à tracer. - une liste
Y
contenant toutes les ordonnées des points à tracer.
5.1 Exemple⚓︎
Python | |
---|---|
plt.plot(X, Y, 'ro')
:
X
sont les abscisses,Y
sont les ordonnées,'ro'
signifie :
5.2 Application⚓︎
Exercice 6
Afficher sur un graphique tous les joueurs de rugby du Top14, en mettant le poids en abscisse et la taille en ordonnée.
Exercice 7
Faire apparaître ensuite les joueurs évoluant au poste de Centre en bleu, et les 2ème lignes en vert.
Correction
# Tests
(insensible à la casse)(Ctrl+I)