txt texto separados por leer guardar datos como comas array archivos archivo abrir c++ csv

texto - ¿Cómo puedo leer y manipular datos de archivos CSV en C++?



leer datos de un archivo.txt en c++ (9)

Esta pregunta ya tiene una respuesta aquí:

Bastante autoexplicativo, probé google y obtuve un montón del temido intercambio de expertos, busqué aquí también en vano. Un tutorial en línea o un ejemplo sería lo mejor. Gracias chicos.


Aquí hay un código que puede usar. Los datos del csv se almacenan dentro de una matriz de filas. Cada fila es una matriz de cadenas. Espero que esto ayude.

#include <iostream> #include <string> #include <fstream> #include <sstream> #include <vector> typedef std::string String; typedef std::vector<String> CSVRow; typedef CSVRow::const_iterator CSVRowCI; typedef std::vector<CSVRow> CSVDatabase; typedef CSVDatabase::const_iterator CSVDatabaseCI; void readCSV(std::istream &input, CSVDatabase &db); void display(const CSVRow&); void display(const CSVDatabase&); int main(){ std::fstream file("file.csv", std::ios::in); if(!file.is_open()){ std::cout << "File not found!/n"; return 1; } CSVDatabase db; readCSV(file, db); display(db); } void readCSV(std::istream &input, CSVDatabase &db){ String csvLine; // read every line from the stream while( std::getline(input, csvLine) ){ std::istringstream csvStream(csvLine); CSVRow csvRow; String csvCol; // read every element from the line that is seperated by commas // and put it into the vector or strings while( std::getline(csvStream, csvCol, '','') ) csvRow.push_back(csvCol); db.push_back(csvRow); } } void display(const CSVRow& row){ if(!row.size()) return; CSVRowCI i=row.begin(); std::cout<<*(i++); for(;i != row.end();++i) std::cout<<'',''<<*i; } void display(const CSVDatabase& db){ if(!db.size()) return; CSVDatabaseCI i=db.begin(); for(; i != db.end(); ++i){ display(*i); std::cout<<std::endl; } }


Encontré este interesante enfoque:

Utilidad de estructura de CSV a C

Cita: CSVtoC es un programa que toma un archivo CSV o de valores separados por comas como entrada y lo vuelca como una estructura C.

Naturalmente, no puede realizar cambios en el archivo CSV, pero si solo necesita acceso de solo lectura en la memoria a los datos, podría funcionar.


Este es un buen ejercicio para ti mismo para trabajar :)

Debes dividir tu biblioteca en tres partes

  • Cargando el archivo CSV
  • Representando el archivo en la memoria para que pueda modificarlo y leerlo
  • Guardando el archivo CSV nuevamente en el disco

Entonces, estás buscando escribir una clase CSVDocument que contenga:

  • Cargar (archivo const char *);
  • Guardar (const char * file);
  • GetBody

Para que pueda usar su biblioteca de esta manera:

CSVDocument doc; doc.Load("file.csv"); CSVDocumentBody* body = doc.GetBody(); CSVDocumentRow* header = body->GetRow(0); for (int i = 0; i < header->GetFieldCount(); i++) { CSVDocumentField* col = header->GetField(i); cout << col->GetText() << "/t"; } for (int i = 1; i < body->GetRowCount(); i++) // i = 1 so we skip the header { CSVDocumentRow* row = body->GetRow(i); for (int p = 0; p < row->GetFieldCount(); p++) { cout << row->GetField(p)->GetText() << "/t"; } cout << "/n"; } body->GetRecord(10)->SetText("hello world"); CSVDocumentRow* lastRow = body->AddRow(); lastRow->AddField()->SetText("Hey there"); lastRow->AddField()->SetText("Hey there column 2"); doc->Save("file.csv");

Lo que nos da las siguientes interfaces:

class CSVDocument { public: void Load(const char* file); void Save(const char* file); CSVDocumentBody* GetBody(); }; class CSVDocumentBody { public: int GetRowCount(); CSVDocumentRow* GetRow(int index); CSVDocumentRow* AddRow(); }; class CSVDocumentRow { public: int GetFieldCount(); CSVDocumentField* GetField(int index); CSVDocumentField* AddField(int index); }; class CSVDocumentField { public: const char* GetText(); void GetText(const char* text); };

Ahora solo tienes que completar los espacios en blanco desde aquí :)

Créanme cuando digo esto: invertir su tiempo en aprender cómo hacer que las bibliotecas, especialmente las relacionadas con la carga, manipulación y almacenamiento de datos, no solo eliminen su dependencia de la existencia de dichas bibliotecas sino que también lo conviertan en un alrededor de un mejor programador.

:)

EDITAR

No sé cuánto sabes sobre manipulación y análisis de cadenas; así que si te quedas atascado, me encantaría ayudarte.


He trabajado con muchos archivos CSV en mi tiempo. Me gustaría agregar el consejo:

1 - Dependiendo de la fuente (Excel, etc.), las comas o pestañas pueden estar incrustadas en un campo. Por lo general, la regla es que estarán ''protegidos'' porque el campo se delimitará con comillas dobles, como en "Boston, MA 02346".

2 - Algunas fuentes no harán doble cita delimitar todos los campos de texto. Otras fuentes lo harán. Otros delimitarán todos los campos, incluso los numéricos.

3 - Los campos que contienen comillas dobles generalmente obtienen las comillas dobles incrustadas dobladas (y el campo mismo delimitado con comillas dobles, como en "George" "Babe" "Ruth".

4 - Algunas fuentes incrustarán CR / LF (¡Excel es uno de estos!). A veces será solo un CR. El campo generalmente estará delimitado por comillas dobles, pero esta situación es muy difícil de manejar.


Más información sería útil.

Pero la forma más simple:

#include <iostream> #include <sstream> #include <fstream> #include <string> int main() { std::ifstream data("plop.csv"); std::string line; while(std::getline(data,line)) { std::stringstream lineStream(line); std::string cell; while(std::getline(lineStream,cell,'','')) { // You have a cell!!!! } } }

También vea esta pregunta: Analizador de CSV en C ++




Si lo que realmente está haciendo es manipular un archivo CSV, la respuesta de Nelson tiene sentido. Sin embargo, mi sospecha es que el CSV es simplemente un artefacto del problema que estás resolviendo. En C ++, eso probablemente significa que tiene algo así como su modelo de datos:

struct Customer { int id; std::string first_name; std::string last_name; struct { std::string street; std::string unit; } address; char state[2]; int zip; };

Por lo tanto, cuando trabaje con una colección de datos, tiene sentido tener std::vector<Customer> o std::set<Customer> .

Con eso en mente, piense en su manejo de CSV como dos operaciones:

// if you wanted to go nuts, you could use a forward iterator concept for both of these class CSVReader { public: CSVReader(const std::string &inputFile); bool hasNextLine(); void readNextLine(std::vector<std::string> &fields); private: /* secrets */ }; class CSVWriter { public: CSVWriter(const std::string &outputFile); void writeNextLine(const std::vector<std::string> &fields); private: /* more secrets */ }; void readCustomers(CSVReader &reader, std::vector<Customer> &customers); void writeCustomers(CSVWriter &writer, const std::vector<Customer> &customers);

Lea y escriba una sola fila a la vez, en lugar de mantener una representación completa en memoria del archivo en sí. Hay algunos beneficios obvios:

  1. Sus datos están representados en una forma que tiene sentido para su problema (clientes), en lugar de la solución actual (archivos CSV).
  2. Puede agregar adaptadores de forma trivial para otros formatos de datos, como importación / exportación de SQL masivo, archivos de hoja de cálculo de Excel / OO o incluso un procesamiento de HTML <table> .
  3. Es probable que su huella de memoria sea más pequeña (depende del tamaño relativo de sizeof(Customer) frente al número de bytes en una sola fila).
  4. CSVReader y CSVWriter se pueden reutilizar como base para un modelo en memoria (como el de Nelson) sin pérdida de rendimiento o funcionalidad. Lo contrario no es verdad.

Usando tokenizer de impulso para analizar los registros , mira aquí para más detalles .

ifstream in(data.c_str()); if (!in.is_open()) return 1; typedef tokenizer< escaped_list_separator<char> > Tokenizer; vector< string > vec; string line; while (getline(in,line)) { Tokenizer tok(line); vec.assign(tok.begin(),tok.end()); /// do something with the record if (vec.size() < 3) continue; copy(vec.begin(), vec.end(), ostream_iterator<string>(cout, "|")); cout << "/n----------------------" << endl; }