# Créer un fichier de test
with open("notes.txt", "w", encoding="utf-8") as f:
f.write("Alice 14\nBob 8\nCharlie 17\nEve 15\n")
print("Fichier créé.")Fichier créé.
Un vrai programme communique avec le monde extérieur : lire une configuration, enregistrer des résultats, importer des données utilisateurs. Python offre une API très simple pour travailler avec les fichiers — mais elle cache quelques pièges classiques que le TOSA teste régulièrement.
open()La fonction native open() renvoie un objet fichier qu’on peut lire, écrire ou fermer.
fichier = open(chemin, mode, encoding="utf-8")| Mode | Effet | Si le fichier n’existe pas |
|---|---|---|
"r" |
Lecture seule (défaut) | Erreur FileNotFoundError |
"w" |
Écriture (écrase !) | Créé |
"a" |
Ajout (append) en fin | Créé |
"x" |
Création exclusive | Créé |
"r+" |
Lecture + écriture | Erreur |
"rb", "wb" |
Lecture/écriture en binaire |
"w" écrase le contenu existant !
Ouvrir en mode "w" vide le fichier avant d’écrire. Si vous voulez ajouter à la fin, utilisez "a".
# ❌ Écrase le fichier s'il existe
f = open("log.txt", "w")
# ✅ Ajoute à la fin
f = open("log.txt", "a")Spécifiez toujours encoding="utf-8" pour les fichiers texte — c’est la norme universelle pour gérer les accents, caractères spéciaux, etc.
open("fichier.txt", "r", encoding="utf-8")Sans cet argument, Python utilise l’encodage système par défaut, ce qui crée des bugs d’affichage selon les plateformes (notamment avec les accents sur Windows).
Créons d’abord un fichier de test, puis lisons-le.
# Créer un fichier de test
with open("notes.txt", "w", encoding="utf-8") as f:
f.write("Alice 14\nBob 8\nCharlie 17\nEve 15\n")
print("Fichier créé.")Fichier créé.
read()Renvoie toute la contenu du fichier comme une chaîne.
with open("notes.txt", "r", encoding="utf-8") as f:
contenu = f.read()
print(repr(contenu))'Alice 14\nBob 8\nCharlie 17\nEve 15\n'
La méthode recommandée : itérer directement sur le fichier.
with open("notes.txt", "r", encoding="utf-8") as f:
for ligne in f:
print(repr(ligne))'Alice 14\n'
'Bob 8\n'
'Charlie 17\n'
'Eve 15\n'
\n à la fin de chaque ligne
Quand vous lisez ligne par ligne, chaque ligne conserve son \n de fin. Pour l’enlever, utilisez .rstrip() ou .strip() :
with open("notes.txt", "r", encoding="utf-8") as f:
for ligne in f:
ligne = ligne.rstrip("\n") # enlève le \n final
print(repr(ligne))'Alice 14'
'Bob 8'
'Charlie 17'
'Eve 15'
readlines()with open("notes.txt", "r", encoding="utf-8") as f:
lignes = f.readlines()
print(lignes)['Alice 14\n', 'Bob 8\n', 'Charlie 17\n', 'Eve 15\n']
Attention : readlines() charge toutes les lignes en mémoire. Pour un gros fichier, préférez itérer.
| Méthode | Renvoie | Usage |
|---|---|---|
f.read() |
Chaîne complète | Petits fichiers |
f.read(n) |
n caractères |
Lecture contrôlée |
f.readline() |
Une ligne | Lecture manuelle |
f.readlines() |
Liste de toutes les lignes | Lecture complète |
for ligne in f: |
Itérateur ligne par ligne | Recommandé — efficace |
write() — écrire une chaînewith open("rapport.txt", "w", encoding="utf-8") as f:
f.write("Rapport du jour\n")
f.write("================\n")
f.write("Ventes : 1250 €\n")
f.write("Clients : 15\n")
# Vérifier le résultat
with open("rapport.txt", "r", encoding="utf-8") as f:
print(f.read())Rapport du jour
================
Ventes : 1250 €
Clients : 15
write() n’ajoute PAS de \n automatique
Contrairement à print, write n’ajoute rien à la fin. Oubliez le \n et tout sera sur la même ligne :
# ❌ Tout sur une ligne
f.write("Alice")
f.write("Bob")
# → "AliceBob"
# ✅ Ajoutez \n manuellement
f.write("Alice\n")
f.write("Bob\n")writelines() — écrire plusieurs lignesPrend une séquence de chaînes. Attention : n’ajoute pas de \n entre elles non plus !
lignes = ["Alice 14\n", "Bob 8\n", "Charlie 17\n"]
with open("notes.txt", "w", encoding="utf-8") as f:
f.writelines(lignes)
with open("notes.txt", "r", encoding="utf-8") as f:
print(f.read())Alice 14
Bob 8
Charlie 17
"a"Pour ajouter à la fin sans écraser :
with open("rapport.txt", "a", encoding="utf-8") as f:
f.write("\nMise à jour 14h30\n")
f.write("Ventes : 1400 €\n")
with open("rapport.txt", "r", encoding="utf-8") as f:
print(f.read())Rapport du jour
================
Ventes : 1250 €
Clients : 15
Mise à jour 14h30
Ventes : 1400 €
withVous l’avez vu dans tous les exemples. Le with garantit que le fichier est automatiquement fermé, même en cas d’erreur.
with (à éviter)# ❌ Approche verbeuse et risquée
f = open("fichier.txt", "r", encoding="utf-8")
try:
contenu = f.read()
finally:
f.close()with (recommandé)# ✅ Concis et sûr
with open("fichier.txt", "r", encoding="utf-8") as f:
contenu = f.read()
# f est automatiquement fermé à la sortie du blocwith ?
try/finally ni de close().Utilisez with systématiquement pour les fichiers.
Les fichiers peuvent ne pas exister, ne pas être accessibles… Combinez avec try/except :
def lire_fichier(chemin):
try:
with open(chemin, "r", encoding="utf-8") as f:
return f.read()
except FileNotFoundError:
print(f"Fichier introuvable : {chemin}")
return None
except PermissionError:
print(f"Accès refusé : {chemin}")
return None
contenu = lire_fichier("n_existe_pas.txt")
print(contenu)Fichier introuvable : n_existe_pas.txt
None
JSON (JavaScript Object Notation) est le format universel pour échanger des données structurées. Python lit et écrit du JSON avec le module json de la bibliothèque standard.
| JSON | Python |
|---|---|
object {...} |
dict |
array [...] |
list |
string |
str |
number (entier) |
int |
number (flottant) |
float |
true, false |
True, False |
null |
None |
json.dump()import json
donnees = {
"nom": "Alice",
"age": 30,
"notes": [14, 15, 12],
"admin": True,
}
with open("data.json", "w", encoding="utf-8") as f:
json.dump(donnees, f, ensure_ascii=False, indent=2)
# Vérifier
with open("data.json", "r", encoding="utf-8") as f:
print(f.read()){
"nom": "Alice",
"age": 30,
"notes": [
14,
15,
12
],
"admin": true
}
Options utiles :
indent=2 : indente le JSON pour le rendre lisible.ensure_ascii=False : garde les accents (sans ça, é devient \u00e9).sort_keys=True : trie les clés alphabétiquement.json.load()import json
with open("data.json", "r", encoding="utf-8") as f:
donnees = json.load(f)
print(donnees)
print(type(donnees))
print(donnees["notes"]){'nom': 'Alice', 'age': 30, 'notes': [14, 15, 12], 'admin': True}
<class 'dict'>
[14, 15, 12]
Si vous travaillez avec du JSON en mémoire (sans fichier) :
json.dumps(obj) (dump string) : Python → chaîne JSON.json.loads(chaine) (load string) : chaîne JSON → Python.import json
d = {"a": 1, "liste": [1, 2, 3]}
chaine = json.dumps(d)
print(chaine)
print(type(chaine))
reconstitue = json.loads(chaine)
print(reconstitue){"a": 1, "liste": [1, 2, 3]}
<class 'str'>
{'a': 1, 'liste': [1, 2, 3]}
Moyen mnémotechnique :
dump / load : fichier (on donne un objet file).dumps / loads : string (on donne une chaîne).JSON ne sait pas sérialiser :
import json
json.dumps({1, 2, 3}) # set non supporté--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[13], line 2 1 import json ----> 2 json.dumps({1, 2, 3}) # set non supporté File ~\AppData\Local\Programs\Python\Python312\Lib\json\__init__.py:231, in dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, cls, indent, separators, default, sort_keys, **kw) 226 # cached encoder 227 if (not skipkeys and ensure_ascii and 228 check_circular and allow_nan and 229 cls is None and indent is None and separators is None and 230 default is None and not sort_keys and not kw): --> 231 return _default_encoder.encode(obj) 232 if cls is None: 233 cls = JSONEncoder File ~\AppData\Local\Programs\Python\Python312\Lib\json\encoder.py:200, in JSONEncoder.encode(self, o) 196 return encode_basestring(o) 197 # This doesn't pass the iterator directly to ''.join() because the 198 # exceptions aren't as detailed. The list call should be roughly 199 # equivalent to the PySequence_Fast that ''.join() would do. --> 200 chunks = self.iterencode(o, _one_shot=True) 201 if not isinstance(chunks, (list, tuple)): 202 chunks = list(chunks) File ~\AppData\Local\Programs\Python\Python312\Lib\json\encoder.py:258, in JSONEncoder.iterencode(self, o, _one_shot) 253 else: 254 _iterencode = _make_iterencode( 255 markers, self.default, _encoder, self.indent, floatstr, 256 self.key_separator, self.item_separator, self.sort_keys, 257 self.skipkeys, _one_shot) --> 258 return _iterencode(o, 0) File ~\AppData\Local\Programs\Python\Python312\Lib\json\encoder.py:180, in JSONEncoder.default(self, o) 161 def default(self, o): 162 """Implement this method in a subclass such that it returns 163 a serializable object for ``o``, or calls the base implementation 164 (to raise a ``TypeError``). (...) 178 179 """ --> 180 raise TypeError(f'Object of type {o.__class__.__name__} ' 181 f'is not JSON serializable') TypeError: Object of type set is not JSON serializable
Pour ces cas, utilisez pickle (sérialisation binaire Python) ou convertissez avant.
CSV (Comma-Separated Values) est le format tabulaire universel, lisible par Excel, tableurs, bases de données. Python fournit le module csv.
import csv
donnees = [
["nom", "age", "ville"],
["Alice", 30, "Paris"],
["Bob", 25, "Lyon"],
["Charlie", 35, "Marseille"],
]
with open("personnes.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerows(donnees)
# Vérifier
with open("personnes.csv", "r", encoding="utf-8") as f:
print(f.read())nom,age,ville
Alice,30,Paris
Bob,25,Lyon
Charlie,35,Marseille
newline="" obligatoire !
Le paramètre newline="" dans open() est indispensable en écriture CSV. Sans lui, Windows produit des doubles retours à la ligne (bug silencieux).
Règle : toujours newline="" pour les CSV.
import csv
with open("personnes.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f)
for ligne in reader:
print(ligne)['nom', 'age', 'ville']
['Alice', '30', 'Paris']
['Bob', '25', 'Lyon']
['Charlie', '35', 'Marseille']
Chaque ligne est une liste de chaînes. Les nombres sont lus comme des chaînes — il faut convertir si besoin :
import csv
with open("personnes.csv", "r", encoding="utf-8") as f:
reader = csv.reader(f)
header = next(reader) # récupérer l'en-tête
for ligne in reader:
nom, age, ville = ligne
age = int(age) # conversion
print(f"{nom} ({age}) vit à {ville}")Alice (30) vit à Paris
Bob (25) vit à Lyon
Charlie (35) vit à Marseille
DictReaderPlus pratique pour manipuler les données par nom de colonne :
import csv
with open("personnes.csv", "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
for ligne in reader:
print(f"{ligne['nom']} → {ligne['ville']}")Alice → Paris
Bob → Lyon
Charlie → Marseille
DictReader utilise la première ligne comme en-tête pour nommer les colonnes.
DictWriterimport csv
donnees = [
{"nom": "Alice", "age": 30, "ville": "Paris"},
{"nom": "Bob", "age": 25, "ville": "Lyon"},
]
with open("sortie.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["nom", "age", "ville"])
writer.writeheader()
writer.writerows(donnees)
with open("sortie.csv", "r", encoding="utf-8") as f:
print(f.read())nom,age,ville
Alice,30,Paris
Bob,25,Lyon
En France, on utilise souvent ; au lieu de , (car la virgule est utilisée comme séparateur décimal). On précise avec delimiter=";" :
import csv
# Écrire en CSV « français »
with open("fr.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f, delimiter=";")
writer.writerow(["produit", "prix"])
writer.writerow(["pain", "1,20"])
writer.writerow(["lait", "0,95"])
with open("fr.csv", "r", encoding="utf-8") as f:
print(f.read())produit;prix
pain;1,20
lait;0,95
Pour les images, PDF, ZIP… il faut lire en mode binaire ("rb" / "wb").
# Copier un fichier binaire
with open("source.png", "rb") as src:
contenu = src.read()
with open("destination.png", "wb") as dst:
dst.write(contenu)Le mode binaire renvoie des bytes (b"...") au lieu de strings. Ce n’est généralement pas utile au niveau Avancé du TOSA, mais à reconnaître.
pathlib : chemins modernesLe module pathlib offre une API objet pour les chemins de fichiers. Plus lisible que os.path.
from pathlib import Path
p = Path("notes.txt")
# Informations
print(f"Existe ? : {p.exists()}")
print(f"Est un fichier ? : {p.is_file()}")
print(f"Taille : {p.stat().st_size} octets")
print(f"Nom : {p.name}")
print(f"Extension : {p.suffix}")
# Lire/écrire sans open() — pratique pour les petits fichiers
contenu = p.read_text(encoding="utf-8")
print(f"Début : {contenu[:50]}...")Existe ? : True
Est un fichier ? : True
Taille : 29 octets
Nom : notes.txt
Extension : .txt
Début : Alice 14
Bob 8
Charlie 17
...
pathlib permet aussi la concaténation avec / :
from pathlib import Path
dossier = Path("/home/user/documents")
fichier = dossier / "rapport.txt"
# fichier vaut Path("/home/user/documents/rapport.txt")On approfondira pathlib en Partie 4.
Nettoyage final des fichiers temporaires créés pour les démos :
from pathlib import Path
for nom in ["notes.txt", "rapport.txt", "data.json", "personnes.csv", "sortie.csv", "fr.csv"]:
p = Path(nom)
if p.exists():
p.unlink() # suppression
print("Nettoyage terminé.")Nettoyage terminé.
Que fait open("log.txt", "w") si le fichier existe déjà ?
c) — le mode "w" écrase le contenu existant. Pour ajouter sans perdre les données, utilisez "a" (append).
Pourquoi utiliser with open(...) as f: plutôt que f = open(...) ?
b) — le context manager garantit la fermeture automatique, y compris si une exception survient. C’est la manière moderne et sûre.
Quelle est la bonne approche pour parcourir un gros fichier texte ?
f.read() puis split("\n")f.readlines() puis bouclefor ligne in f:f.read(99999999)c) — la boucle directe n’utilise pas de mémoire supplémentaire (lit ligne par ligne). read() et readlines() chargent tout en mémoire.
Que renvoie json.dumps({"a": 1}) ?
'{"a": 1}'b) — dumps (string) renvoie une chaîne. Ne pas confondre avec dump (fichier).
import json
print(json.dumps({"a": 1}))
print(type(json.dumps({"a": 1}))){"a": 1}
<class 'str'>
Pourquoi faut-il newline="" avec un fichier CSV ?
b) — sans newline="", le module csv et Windows ajoutent chacun un \n, produisant des doubles sauts de ligne. Règle : toujours newline="" en écriture CSV.
Quelle est la bonne correspondance ?
json.load → chaîne JSON vers objet Pythonjson.loads → fichier JSON vers objet Pythonjson.dump → objet Python vers fichier JSONjson.dumps → objet Python vers fichier JSONc) — dump écrit dans un fichier, dumps renvoie une string. Moyen mnémo : le s final, c’est « string ».
| Vers objet | Depuis objet | |
|---|---|---|
| Fichier | json.load(f) |
json.dump(obj, f) |
| Chaîne | json.loads(s) |
json.dumps(obj) |
Quelle exception est levée par open("absent.txt", "r") si le fichier n’existe pas ?
ValueErrorNameErrorFileNotFoundErrorPermissionErrorc) FileNotFoundError — sous-classe d’OSError. À rattraper dans un try/except pour traiter ce cas proprement.
Créez un fichier notes.txt contenant une note par ligne, puis écrivez une fonction statistiques(chemin) qui renvoie un dict avec min, max, moyenne, nb.
def statistiques(chemin):
...
# Créer un fichier de test
with open("notes.txt", "w", encoding="utf-8") as f:
f.write("12\n15\n9\n17\n11\n")
print(statistiques("notes.txt"))def statistiques(chemin):
try:
with open(chemin, "r", encoding="utf-8") as f:
notes = [int(ligne.strip()) for ligne in f if ligne.strip()]
except FileNotFoundError:
return None
if not notes:
return {"nb": 0, "min": None, "max": None, "moyenne": None}
return {
"nb": len(notes),
"min": min(notes),
"max": max(notes),
"moyenne": round(sum(notes) / len(notes), 2),
}
# Créer un fichier de test
with open("notes.txt", "w", encoding="utf-8") as f:
f.write("12\n15\n9\n17\n11\n")
print(statistiques("notes.txt"))
print(statistiques("n_existe_pas.txt"))
# Nettoyage
from pathlib import Path
Path("notes.txt").unlink(){'nb': 5, 'min': 9, 'max': 17, 'moyenne': 12.8}
None
[int(ligne.strip()) for ligne in f] — lecture + conversion en une ligne.if ligne.strip() — ignorer les lignes vides.try/except pour le cas où le fichier n’existe pas.Créez deux fonctions :
sauver(catalogue, chemin) : écrit une liste de dicts en JSON.charger(chemin) : relit le fichier et renvoie la liste.Testez avec un catalogue de livres.
import json
def sauver(catalogue, chemin):
...
def charger(chemin):
...
catalogue = [
{"titre": "Dune", "auteur": "Herbert", "annee": 1965},
{"titre": "1984", "auteur": "Orwell", "annee": 1949},
]
sauver(catalogue, "catalogue.json")
loaded = charger("catalogue.json")
print(loaded)import json
from pathlib import Path
def sauver(catalogue, chemin):
with open(chemin, "w", encoding="utf-8") as f:
json.dump(catalogue, f, ensure_ascii=False, indent=2)
def charger(chemin):
try:
with open(chemin, "r", encoding="utf-8") as f:
return json.load(f)
except FileNotFoundError:
return []
catalogue = [
{"titre": "Dune", "auteur": "Herbert", "annee": 1965},
{"titre": "1984", "auteur": "Orwell", "annee": 1949},
{"titre": "L'Étranger", "auteur": "Camus", "annee": 1942},
]
sauver(catalogue, "catalogue.json")
# Vérifier le contenu du fichier
with open("catalogue.json", "r", encoding="utf-8") as f:
print(f.read())
# Recharger
loaded = charger("catalogue.json")
print("\nDonnées rechargées :")
for livre in loaded:
print(f" - {livre['titre']} ({livre['annee']})")
# Nettoyage
Path("catalogue.json").unlink()[
{
"titre": "Dune",
"auteur": "Herbert",
"annee": 1965
},
{
"titre": "1984",
"auteur": "Orwell",
"annee": 1949
},
{
"titre": "L'Étranger",
"auteur": "Camus",
"annee": 1942
}
]
Données rechargées :
- Dune (1965)
- 1984 (1949)
- L'Étranger (1942)
Soit un dictionnaire d’étudiants. Exportez-le en CSV avec les colonnes nom, moyenne, mention.
import csv
etudiants = {
"Alice": {"moyenne": 14.5, "mention": "Bien"},
"Bob": {"moyenne": 9.8, "mention": "Insuffisant"},
"Charlie": {"moyenne": 17.0, "mention": "Très bien"},
}
def exporter_csv(etudiants, chemin):
...
exporter_csv(etudiants, "classe.csv")import csv
from pathlib import Path
etudiants = {
"Alice": {"moyenne": 14.5, "mention": "Bien"},
"Bob": {"moyenne": 9.8, "mention": "Insuffisant"},
"Charlie": {"moyenne": 17.0, "mention": "Très bien"},
"Diana": {"moyenne": 12.3, "mention": "Assez bien"},
}
def exporter_csv(etudiants, chemin):
with open(chemin, "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f, delimiter=";")
writer.writerow(["nom", "moyenne", "mention"])
for nom, infos in etudiants.items():
writer.writerow([nom, infos["moyenne"], infos["mention"]])
exporter_csv(etudiants, "classe.csv")
# Relire et afficher
with open("classe.csv", "r", encoding="utf-8") as f:
print(f.read())
# Nettoyage
Path("classe.csv").unlink()nom;moyenne;mention
Alice;14.5;Bien
Bob;9.8;Insuffisant
Charlie;17.0;Très bien
Diana;12.3;Assez bien
import csv
from pathlib import Path
etudiants = {
"Alice": {"moyenne": 14.5, "mention": "Bien"},
"Bob": {"moyenne": 9.8, "mention": "Insuffisant"},
}
def exporter_csv_v2(etudiants, chemin):
# Construire une liste de dicts plats
lignes = [{"nom": nom, **infos} for nom, infos in etudiants.items()]
with open(chemin, "w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["nom", "moyenne", "mention"], delimiter=";")
writer.writeheader()
writer.writerows(lignes)
exporter_csv_v2(etudiants, "classe2.csv")
with open("classe2.csv", "r", encoding="utf-8") as f:
print(f.read())
Path("classe2.csv").unlink()nom;moyenne;mention
Alice;14.5;Bien
Bob;9.8;Insuffisant
Créez une fonction logger(message, fichier="log.txt") qui ajoute à la fin du fichier une ligne au format "[2026-04-22 14:30:00] message".
from datetime import datetime
def logger(message, fichier="log.txt"):
...
logger("Démarrage de l'application")
logger("Utilisateur connecté : Alice")
logger("Erreur : fichier introuvable")from datetime import datetime
from pathlib import Path
def logger(message, fichier="log.txt"):
horodatage = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
with open(fichier, "a", encoding="utf-8") as f:
f.write(f"[{horodatage}] {message}\n")
# Écrire quelques lignes
logger("Démarrage de l'application")
logger("Utilisateur connecté : Alice")
logger("Erreur : fichier introuvable")
# Afficher le log
with open("log.txt", "r", encoding="utf-8") as f:
print(f.read())
# Nettoyage
Path("log.txt").unlink()[2026-04-22 14:28:45] Démarrage de l'application
[2026-04-22 14:28:45] Utilisateur connecté : Alice
[2026-04-22 14:28:45] Erreur : fichier introuvable
"a" (append) : ajoute à la fin, ne remplace jamais.datetime.now().strftime(...) : formater la date courante.logging).with open(...) as f: est la manière standard d’ouvrir un fichier. Fermeture automatique garantie."r" (lecture), "w" (écriture — écrase !), "a" (ajout), "x" (création exclusive).encoding="utf-8" pour du texte.for ligne in f: (pas readlines() sur de gros fichiers).write n’ajoute pas de \n automatique — pensez-y.json.dump / json.load pour fichier, json.dumps / json.loads pour chaîne.csv.reader / csv.writer ou DictReader / DictWriter. newline="" obligatoire.pathlib.Path offre une API objet moderne pour les chemins.try/except FileNotFoundError pour gérer les fichiers absents.← Chapitre précédent : Exceptions • Chapitre suivant : pip et l’écosystème →