HOWTO · C++

Leer archivo CSV en C++

Este artículo muestra cómo leer un archivo CSV en C++

En esta página

Para leer en C++ un archivo sencillo delimitado por comas, lee una línea a la vez con std::getline y luego divide esa línea en campos con una segunda llamada a std::getline. Este método funciona cuando cada línea física corresponde a un registro y las comas solo separan campos. El ejemplo siguiente crea su propio archivo de entrada pequeño, así que puedes compilarlo y ejecutarlo sin preparar otro archivo de datos.

Leer un archivo CSV con std::getline y std::istringstream

Primero, el programa escribe dos registros en grades.csv y luego abre el archivo para leerlo. El std::getline externo lee una línea física en un std::string; std::istringstream convierte esa línea en un flujo y el std::getline interno usa la coma como delimitador para extraer cada campo. Cada registro se convierte en un std::vector<std::string> y el conjunto de registros se almacena en otro vector. Así se conserva el orden original y se evita usar un mapa con claves enteras cuando las filas simplemente aparecen en secuencia.

Ejecuta este programa autocontenido. El código y las etiquetas visibles de la salida se mantienen en inglés:

#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;
}

El resultado de ejecución proporcionado para la ejecución correcta aparece a continuación. Las etiquetas Name y Score permanecen en inglés:

Name | Score
Ada Lovelace | 98
Grace Hopper | 95

Si falla la creación o la apertura del archivo, se escribe un error en std::cerr y se devuelve el estado 1; en la ruta normal se devuelve el estado 0. En tu propio programa, comprueba que el flujo de entrada se haya abierto correctamente antes de leer. Si el archivo procede de fuera del programa, informa de su ruta y gestiona el fallo de apertura según las necesidades de tu aplicación; no des por hecho que el archivo existe.

Gestionar los espacios en blanco en los campos CSV

El tratamiento de los espacios en blanco es una decisión sobre los datos; no forma parte automática de la separación en campos. trimEnds elimina los espacios en blanco solo del principio y del final de cada campo extraído. Conserva los espacios dentro de un valor como Ada Lovelace. La conversión a unsigned char antes de llamar a std::isspace evita pasar un valor negativo de tipo char simple a esa función de clasificación de caracteres.

En algunos archivos, los espacios después de una coma se consideran formato; en otros, forman parte del campo. Recorta los extremos solo si eso coincide con el contrato de datos que necesitas preservar. Eliminar todos los espacios en blanco también uniría las palabras de un nombre o una dirección; recortar ambos extremos cambia el contenido inicial y final. Si los espacios en blanco tienen significado en los datos de origen, conserva el campo tal como se leyó o aplica una regla más específica, como eliminar solo los espacios ASCII.

El bucle de separación también tiene una consecuencia sencilla para los campos vacíos: dos comas consecutivas entre otros valores producen una cadena vacía entre ellas. Una coma al final no hace que este bucle de std::getline añada un último campo vacío; si el formato de entrada lo requiere, gestiona explícitamente ese delimitador final. Conserva o descarta los valores vacíos según las columnas esperadas. Si una línea tiene menos campos que la cabecera, gestiona ese caso explícitamente antes de acceder a los elementos de la fila por índice; el breve bucle de visualización anterior presupone que están presentes ambas columnas.

Comprender los límites de la separación por delimitadores

Este método divide cada línea física en cada coma. No interpreta las comillas del formato CSV. Por ejemplo, un valor como "Paris, France" se divide en dos partes, aunque un lector CSV debería tratar el texto entrecomillado como un solo campo. Tampoco decodifica las comillas escapadas dentro de campos entrecomillados, y confunde una nueva línea dentro de un campo entrecomillado con el final de un registro. Además, los registros pueden tener distinto número de campos, así que no des por hecho que todas las líneas contienen el mismo número de comas.

Usa este método con datos sencillos y controlados cuyas reglas garanticen un registro por línea y que no haya delimitadores entrecomillados. Para archivos CSV de uso general, utiliza un analizador CSV que implemente el dialecto de los datos, incluidas sus reglas de comillas y escapes. Incluso después de analizar el archivo, valida el número y el significado de los campos que requiere tu aplicación. Las operaciones de flujo estándar que se muestran aquí permiten leer archivos y líneas; por sí solas no implementan toda la gramática del formato CSV.