Fichiers et formats de données

Lire et écrire du CSV, du JSON et du Parquet en Python, en lien avec les formats vus côté data engineering.

Créé le 19 août 2026·Mis à jour le 19 août 2026

Introduction


Un script Python data passe une grande partie de son temps à lire et écrire des fichiers : CSV exportés d'un système tiers, JSON reçus d'une API, Parquet stocké dans un data lake. Les mécanismes de base reposent sur la bibliothèque standard et sur la gestion des chemins avec pathlib, en s'appuyant sur les notions de formats de fichiers du cours data engineer.

Context managers : with open(...)


Avant d'ouvrir un fichier, un mécanisme du langage mérite d'être compris : le context manager, introduit par le mot-clé with.

with open("donnees.txt") as fichier:
    contenu = fichier.read()
    print(contenu)

# à la sortie du bloc with, le fichier est automatiquement fermé,
# que le bloc se termine normalement ou par une exception

Le bloc with garantit que le fichier est fermé proprement en sortie du bloc, y compris si une exception survient à l'intérieur. C'est l'équivalent Python d'un try/finally qui fermerait systématiquement la ressource, mais condensé dans une syntaxe dédiée.

# Équivalent manuel, sans with, à ne pas faire en pratique
fichier = open("donnees.txt")
try:
    contenu = fichier.read()
finally:
    fichier.close()

💡 Bon à savoir : le principe rejoint la gestion de ressources en PHP, où un fichier ouvert avec fopen() doit être explicitement refermé avec fclose(), généralement dans un bloc finally, ou confié à un objet dont le destructeur s'en charge. Le with de Python rend ce nettoyage automatique et impossible à oublier, pour tout objet qui implémente le protocole de context manager (les méthodes __enter__ et __exit__).

Plusieurs fichiers peuvent être ouverts dans un seul bloc with :

with open("source.csv") as entree, open("resultat.csv", "w") as sortie:
    sortie.write(entree.read())

Lecture et écriture de CSV avec la stdlib


Le module csv fait partie de la bibliothèque standard et gère correctement les subtilités du format (guillemets, séparateurs contenus dans une valeur, encodage), plutôt qu'un simple découpage de chaque ligne par la virgule.

import csv

# Lecture ligne par ligne, chaque ligne est une liste de chaînes
with open("utilisateurs.csv", newline="", encoding="utf-8") as fichier:
    lecteur = csv.reader(fichier)
    en_tete = next(lecteur)  # ["id", "nom", "email"]
    for ligne in lecteur:
        print(ligne)  # ["1", "Alice", "alice@mail.com"]

csv.DictReader va plus loin en exposant chaque ligne comme un dictionnaire, en s'appuyant sur la première ligne comme en-tête, ce qui rend le code moins dépendant de l'ordre des colonnes :

with open("utilisateurs.csv", newline="", encoding="utf-8") as fichier:
    lecteur = csv.DictReader(fichier)
    for ligne in lecteur:
        print(ligne["nom"], ligne["email"])

L'écriture suit le même principe, avec csv.writer ou csv.DictWriter :

with open("export.csv", "w", newline="", encoding="utf-8") as fichier:
    ecrivain = csv.DictWriter(fichier, fieldnames=["id", "nom", "email"])
    ecrivain.writeheader()
    ecrivain.writerow({"id": 1, "nom": "Alice", "email": "alice@mail.com"})
    ecrivain.writerow({"id": 2, "nom": "Bob", "email": "bob@mail.com"})

💡 Bon à savoir : l'argument newline="" à l'ouverture du fichier n'est pas une fantaisie, il évite un bug classique sous Windows où le module csv insère des lignes vides supplémentaires si la traduction automatique des fins de ligne du système n'est pas désactivée.

Lecture et écriture de JSON avec la stdlib


Le module json convertit directement entre chaînes JSON et structures Python natives (dict, list, str, int, float, bool, None), sans étape de configuration.

import json

# Lecture d'un fichier JSON
with open("utilisateur.json", encoding="utf-8") as fichier:
    donnees = json.load(fichier)
    print(donnees["nom"])

# Écriture d'un fichier JSON
utilisateur = {"id": 1, "nom": "Alice", "actif": True}
with open("export.json", "w", encoding="utf-8") as fichier:
    json.dump(utilisateur, fichier, indent=2, ensure_ascii=False)

# Conversion chaîne <-> objet, sans passer par un fichier
texte = json.dumps(utilisateur)          # dict -> str
utilisateur_relu = json.loads(texte)      # str -> dict

Le principe est le même qu'avec json_encode/json_decode en PHP : dump/dumps sérialisent (encodent), load/loads désérialisent (décodent). Le suffixe s (pour "string") distingue les fonctions qui travaillent directement sur une chaîne de celles qui travaillent sur un fichier ouvert.

OpérationPHPPython
Objet/dict vers chaîne JSONjson_encode($donnees)json.dumps(donnees)
Objet/dict vers fichier JSONfile_put_contents($f, json_encode($donnees))json.dump(donnees, fichier)
Chaîne JSON vers dictjson_decode($texte, true)json.loads(texte)
Fichier JSON vers dictjson_decode(file_get_contents($f), true)json.load(fichier)

💡 Bon à savoir : l'option ensure_ascii=False évite que les caractères accentués soient échappés sous forme d'entités unicode (é au lieu de é) dans le fichier produit, un détail utile dès que le JSON exporté doit rester directement lisible.

Aperçu rapide avec pandas


Pour un usage data au-delà d'un simple script, pandas (voir la leçon Pandas : manipulation de données) simplifie nettement la lecture de fichiers tabulaires, avec une seule ligne pour charger un CSV complet dans une structure exploitable directement pour l'analyse.

import pandas as pd

# Lecture d'un CSV en une ligne, avec inférence automatique des types de colonnes
df = pd.read_csv("utilisateurs.csv")

# Lecture d'un JSON en une ligne
df = pd.read_json("utilisateurs.json")

# Écriture
df.to_csv("export.csv", index=False)
df.to_json("export.json", orient="records")

Cette approche fait plus que le module csv de la stdlib : pandas infère automatiquement les types de colonnes, gère nativement les valeurs manquantes, et retourne une structure (DataFrame) directement prête pour du filtrage, de l'agrégation ou du calcul statistique. La stdlib (csv, json) reste pertinente pour des scripts simples ou des besoins de contrôle fin, pendant que pandas devient l'outil de choix dès qu'une véritable analyse de données commence.

Gestion des chemins avec pathlib


pathlib est le module moderne de gestion des chemins de fichiers, qui remplace l'ancienne approche par chaînes de caractères concaténées et fonctions du module os.path. Il représente un chemin comme un objet, avec des méthodes plutôt que des manipulations de chaînes.

from pathlib import Path

dossier_donnees = Path("data") / "raw"
fichier = dossier_donnees / "utilisateurs.csv"

print(fichier)             # data/raw/utilisateurs.csv
print(fichier.exists())     # True ou False
print(fichier.suffix)       # .csv
print(fichier.stem)         # utilisateurs
print(fichier.parent)       # data/raw

# créer un dossier, y compris les parents manquants, sans erreur s'il existe déjà
dossier_donnees.mkdir(parents=True, exist_ok=True)

# lister tous les fichiers CSV d'un dossier
for chemin_csv in dossier_donnees.glob("*.csv"):
    print(chemin_csv)

# lecture/écriture rapide, sans passer explicitement par open()
contenu = fichier.read_text(encoding="utf-8")
fichier.write_text("nouvelles données", encoding="utf-8")

L'opérateur / surchargé pour concaténer des segments de chemin (dossier_donnees / "utilisateurs.csv") est la première chose qui surprend en venant de PHP, où la construction d'un chemin se fait généralement par concaténation de chaînes avec DIRECTORY_SEPARATOR ou une fonction dédiée. pathlib gère automatiquement les différences entre systèmes d'exploitation (séparateur / ou \), ce qui évite les bugs de portabilité liés à des chemins codés en dur.

Parquet


Le format Parquet est présenté en détail dans la leçon Formats de fichiers et sérialisation du cours data engineer : format binaire orienté colonne, avec schéma embarqué, pensé pour la lecture sélective de colonnes et une forte compression. Ce qui suit se limite à son usage concret en Python.

La lecture et l'écriture de Parquet passent presque toujours par pandas, qui s'appuie en interne sur la librairie pyarrow (à installer comme dépendance) pour l'implémentation réelle du format.

poetry add pandas pyarrow
import pandas as pd

# Écriture : un DataFrame vers un fichier Parquet
df = pd.read_csv("utilisateurs.csv")
df.to_parquet("utilisateurs.parquet", engine="pyarrow", compression="snappy")

# Lecture : chargement complet
df = pd.read_parquet("utilisateurs.parquet")

# Lecture sélective : ne charge que certaines colonnes,
# ce qui exploite directement l'avantage columnar de Parquet
df = pd.read_parquet("utilisateurs.parquet", columns=["id", "email"])

Le paramètre columns de read_parquet illustre concrètement ce que "orienté colonne" signifie en pratique : demander deux colonnes sur dix ne lit physiquement que ces deux colonnes sur disque, sans jamais charger le reste du fichier en mémoire, contrairement à un CSV qui doit être parcouru ligne par ligne dans son intégralité même si une seule colonne est utile au final.

# Comparaison de taille sur un même jeu de données
df.to_csv("export.csv", index=False)
df.to_parquet("export.parquet", compression="snappy")

import os
print(os.path.getsize("export.csv"))       # généralement plusieurs fois plus volumineux
print(os.path.getsize("export.parquet"))    # compressé, format binaire

💡 Bon à savoir : en dehors des échanges ponctuels ou de l'export vers un tableur, il n'y a généralement pas de raison de choisir CSV plutôt que Parquet pour stocker de la donnée tabulaire de façon durable dans un pipeline Python : le gain de place et de vitesse de lecture est immédiat, pour un coût de mise en œuvre quasi nul grâce à pandas.