HOWTO · C++

Lire le fichier CSV en C++

Cet article montre comment lire un fichier CSV en C++

Sur cette page

Pour lire en C++ un fichier simple dont les champs sont séparés par des virgules, lisez une ligne à la fois avec std::getline, puis séparez cette ligne en champs avec un second appel à std::getline. Cette méthode convient lorsque chaque ligne physique correspond à un enregistrement et que les virgules servent uniquement de séparateurs de champs. L’exemple ci-dessous crée son propre petit fichier d’entrée : vous pouvez donc le compiler et l’exécuter sans préparer de fichier de données séparé.

Lire un fichier CSV avec std::getline et std::istringstream

Le programme écrit d’abord deux enregistrements dans grades.csv, puis ouvre le fichier en lecture. La boucle externe std::getline lit une ligne physique dans un std::string ; std::istringstream transforme cette ligne en flux, puis la boucle interne std::getline utilise la virgule comme délimiteur pour extraire chaque champ. Chaque enregistrement devient un std::vector<std::string>, et l’ensemble des enregistrements est stocké dans un autre vecteur. Cette structure conserve l’ordre d’origine et évite d’utiliser une table associative indexée par des entiers lorsque les lignes se suivent simplement.

Exécutez ce programme autonome. Le code et les libellés affichés dans les blocs restent en anglais.

#include <algorithm>
#include <cctype>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

std::string trimEnds(const std::string& value) {
    const auto first = std::find_if_not(value.begin(), value.end(),
        [](unsigned char ch) { return std::isspace(ch); });
    const auto last = std::find_if_not(value.rbegin(), value.rend(),
        [](unsigned char ch) { return std::isspace(ch); }).base();
    if (first >= last) {
        return "";
    }
    return std::string(first, last);
}

int main() {
    const std::string path = "grades.csv";
    {
        std::ofstream sample(path);
        if (!sample) {
            std::cerr << "Could not create input file\n";
            return 1;
        }
        sample << "Name, Score\nAda Lovelace, 98 \nGrace Hopper, 95\n";
    }

    std::ifstream input(path);
    if (!input) {
        std::cerr << "Could not open input file\n";
        return 1;
    }

    std::vector<std::vector<std::string>> rows;
    std::string record;
    while (std::getline(input, record)) {
        std::istringstream line(record);
        std::vector<std::string> fields;
        std::string field;
        while (std::getline(line, field, ',')) {
            fields.push_back(trimEnds(field));
        }
        rows.push_back(fields);
    }

    for (const auto& row : rows) {
        std::cout << row[0] << " | " << row[1] << '\n';
    }
    return 0;
}

Le résultat fourni pour l’exécution réussie est le suivant. Les noms de colonnes et les autres libellés de cette sortie restent en anglais :

Name | Score
Ada Lovelace | 98
Grace Hopper | 95

En cas d’échec de la création ou de l’ouverture du fichier, le programme écrit un message d’erreur dans std::cerr et renvoie le code 1 ; le déroulement normal renvoie le code 0. Dans votre propre programme, vérifiez que le flux d’entrée s’est bien ouvert avant de lire. Si le fichier provient d’une source externe, indiquez son chemin et gérez l’échec de l’ouverture selon les besoins de votre application, sans supposer que le fichier existe.

Gérer les espaces blancs dans les champs CSV

Le traitement des espaces blancs est un choix de gestion des données, et non une étape automatique du découpage. trimEnds supprime les espaces blancs uniquement au début et à la fin de chaque champ extrait. Les espaces à l’intérieur d’une valeur comme Ada Lovelace sont conservés. La conversion en unsigned char avant l’appel à std::isspace évite de transmettre une valeur négative de type char ordinaire à cette fonction de classification des caractères.

Dans certains fichiers, les espaces après une virgule sont de simples éléments de mise en forme ; dans d’autres, ils font partie du champ. N’appliquez la suppression des espaces aux extrémités que si elle respecte le contrat des données que vous devez conserver. Supprimer tous les espaces blancs réunirait aussi les mots d’un nom ou d’une adresse ; supprimer ceux des deux extrémités modifierait le contenu initial et final. Si les espaces ont un sens dans vos données, conservez le champ tel qu’il a été lu ou appliquez une règle plus ciblée, comme la suppression des seuls espaces ASCII.

La boucle de découpage a aussi une conséquence simple pour les champs vides : deux virgules consécutives entre d’autres éléments produisent une chaîne vide entre elles. Une virgule finale ne fait pas ajouter de champ vide à la fin par cette boucle std::getline ; si votre format d’entrée l’exige, traitez explicitement ce délimiteur final. Conservez les valeurs vides ou rejetez-les selon les colonnes attendues. Si une ligne contient moins de champs que l’en-tête, gérez explicitement ce cas avant d’accéder à un élément de la ligne par son indice ; la courte boucle d’affichage ci-dessus suppose que les deux colonnes sont présentes.

Comprendre les limites du découpage par délimiteur

Cette méthode découpe chaque ligne physique à chaque virgule. Elle ne tient pas compte des guillemets du format CSV. Par exemple, une valeur comme "Paris, France" est divisée en deux morceaux, alors qu’un lecteur CSV devrait traiter le texte entre guillemets comme un seul champ. Les guillemets échappés à l’intérieur de champs entre guillemets ne sont pas non plus décodés, et un saut de ligne dans un champ entre guillemets est pris à tort pour la fin d’un enregistrement. Les enregistrements peuvent aussi contenir des nombres différents de champs : ne supposez donc pas que chaque ligne comporte le même nombre de virgules.

Utilisez cette méthode pour des données simples et contrôlées, dont les règles garantissent un enregistrement par ligne et l’absence de délimiteurs entre guillemets. Pour des fichiers CSV généraux, utilisez un analyseur CSV qui prend en charge le dialecte reçu, notamment ses règles de guillemets et d’échappement. Après l’analyse, validez tout de même le nombre et la signification des champs dont votre application a besoin. Les opérations sur les flux standard présentées ici servent à lire les fichiers et les lignes ; elles ne mettent pas à elles seules en œuvre toute la grammaire du format CSV.