Wie kann ich CSV-Dateidaten in C++ lesen und bearbeiten? [duplicate]

Lesezeit: 8 Minuten

Wie kann ich CSV Dateidaten in C lesen und bearbeiten duplicate
zkwentz

Ziemlich selbsterklärend, ich habe Google ausprobiert und viel von dem gefürchteten Expertenaustausch bekommen, ich habe auch hier vergeblich gesucht. Ein Online-Tutorial oder Beispiel wäre am besten. Danke Leute.

  • Ich habe vor einiger Zeit libcsv geschrieben, es ist ein kleiner und sehr schneller CSV-Parser in C und kann auch von C++ aus verwendet werden. Der Download enthält Dokumentation und Beispielprogramme. Sie können es unter überprüfen sourceforge.net/projects/libcsv.

    – Robert Gamble

    6. Januar 2009 um 5:29 Uhr

  • Wie erwartest du, mehr Repräsentanten zu bekommen, wenn du Antworten als Kommentare gibst, Robert? 😀

    – Jonathan Leffler

    6. Januar 2009 um 5:52 Uhr

  • vielleicht braucht er nicht mehr rep?

    – xxxxxxx

    12. Februar 2010 um 6:44 Uhr

  • @ZamfirKerlukson wurde ungefähr 6 Monate vor dieser Frage gestellt.

    – zkwentz

    23. Februar 2013 um 15:19 Uhr

  • @Shog9 Inwiefern ist dieses Duplikat? Dies wurde vor dieser anderen Frage gestellt.

    – zkwentz

    25. August 2017 um 22:37 Uhr

1646356209 807 Wie kann ich CSV Dateidaten in C lesen und bearbeiten duplicate
Martin York

Mehr Informationen wären nützlich.

Aber die einfachste Form:

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

Siehe auch diese Frage: CSV-Parser in C++

  • Ja, aber was ist der Spaß daran? 😛

    Benutzer19302

    6. Januar 2009 um 5:21 Uhr

  • Komplizierter wird es, wenn Sie Kommas in Zellen zulassen, indem Sie Zellen z. B. in Anführungszeichen setzen, Kommas maskieren oder beides.

    – wilhelmtel

    6. Januar 2009 um 5:28 Uhr

  • Vielen Dank Alter. Wenn ich darf, wie würde ich Daten von einer online gehosteten CSV-Datei erhalten? Würde ich einfach Daten machen (“csvhost.com/plop.csv”) oder gibt es etwas anderes?

    – zkwentz

    6. Januar 2009 um 5:37 Uhr

  • libCURL ist eine einfach zu verwendende C-Bibliothek, die eine entfernte Datei über HTTP(S) abrufen kann. Es gibt andere Frameworks wie POCO (oder wahrscheinlich etwas in Boost oder ACE). Die C++-Standard-E/A-Streams adressieren keinen protokollbewussten Remote-Dateidownload.

    – Tom

    6. Januar 2009 um 5:44 Uhr

  • schöne STL-Version! Ich werde vorsichtig, die Quelle mit Boost-Verrücktheit für die dumme Datei IO zu überladen, wenn es das ist, was ich damit machen werde, das debuggt werden muss.

    – Peter Karasev

    6. April 2011 um 5:47 Uhr

Sie können die Boost Tokenizer-Bibliothek ausprobieren, insbesondere die Escape-Listentrennzeichen

  • Dies ist der beste Weg. escape_list_separator<> verarbeitet Randfälle wie Zeichenfolgen in Anführungszeichen mit Kommas darin korrekt.

    – Ferruccio

    6. Januar 2009 um 12:49 Uhr

  • Zeichenfolgen in Anführungszeichen sind keine Grenzfälle (es sei denn, Sie haben einen Tunnelblick)

    – Tom

    7. Januar 2009 um 5:23 Uhr

Wenn Sie wirklich eine CSV-Datei selbst manipulieren, ist Nelsons Antwort sinnvoll. Mein Verdacht ist jedoch, dass die CSV einfach ein Artefakt des Problems ist, das Sie lösen. In C++ bedeutet das wahrscheinlich, dass Sie so etwas wie das folgende als Datenmodell haben:

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

Wenn Sie also mit einer Sammlung von Daten arbeiten, ist es sinnvoll, sie zu haben std::vector<Customer> oder std::set<Customer>.

Stellen Sie sich Ihre CSV-Verarbeitung in diesem Sinne als zwei Vorgänge vor:

// 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);

Lesen und schreiben Sie jeweils eine einzelne Zeile, anstatt eine vollständige In-Memory-Darstellung der Datei selbst zu behalten. Es gibt ein paar offensichtliche Vorteile:

  1. Ihre Daten werden in einer Form dargestellt, die für Ihr Problem (Kunden) sinnvoll ist, und nicht für die aktuelle Lösung (CSV-Dateien).
  2. Sie können problemlos Adapter für andere Datenformate hinzufügen, z. B. SQL-Massenimport/-export, Excel/OO-Tabellenkalkulationsdateien oder sogar HTML <table> Wiedergabe.
  3. Ihr Speicherbedarf ist wahrscheinlich kleiner (abhängig von relative sizeof(Customer) vs. die Anzahl der Bytes in einer einzelnen Zeile).
  4. CSVReader und CSVWriter kann als Grundlage für ein In-Memory-Modell (wie das von Nelson) ohne Leistungs- oder Funktionsverlust wiederverwendet werden. Die Umkehrung ist nicht wahr.

  • Vorsicht bei Zitaten. Es gibt mehrere Arten von Escapezeichen für CSV. Wenn Ihre Zeichenfolge Kommas enthalten kann, wird sie in Anführungszeichen gesetzt. Wenn es zitiert wird und doppelte Anführungszeichen enthält, haben Sie ein Problem. Ich glaube, Excel entgeht Anführungszeichen, indem es sie verdoppelt, aber ich bin mir nicht sicher.

    Benutzer3458

    6. Januar 2009 um 16:36 Uhr

Ich habe in meiner Zeit mit vielen CSV-Dateien gearbeitet. Ich möchte den Rat hinzufügen:

1 – Abhängig von der Quelle (Excel usw.) können Kommas oder Tabulatoren in ein Feld eingebettet sein. Normalerweise ist die Regel, dass sie „geschützt“ sind, da das Feld durch doppelte Anführungszeichen getrennt wird, wie in „Boston, MA 02346“.

2 – Einige Quellen werden nicht alle Textfelder durch doppelte Anführungszeichen trennen. Andere Quellen werden. Andere begrenzen alle Felder, sogar numerische.

3 – Felder, die doppelte Anführungszeichen enthalten, erhalten normalerweise die eingebetteten doppelten Anführungszeichen (und das Feld selbst wird durch doppelte Anführungszeichen getrennt, wie in “George “”Babe”” Ruth”.

4 – Einige Quellen werden CR/LFs einbetten (Excel ist eine davon!). Manchmal ist es nur ein CR. Das Feld wird normalerweise durch doppelte Anführungszeichen getrennt, aber diese Situation ist sehr schwierig zu handhaben.

Das ist eine gute Übung für dich selbst 🙂

Sie sollten Ihre Bibliothek in drei Teile aufteilen

  • Laden der CSV-Datei
  • Stellt die Datei im Speicher dar, damit Sie sie ändern und lesen können
  • Speichern der CSV-Datei zurück auf die Festplatte

Sie möchten also eine CSVDocument-Klasse schreiben, die Folgendes enthält:

  • Laden (const char* file);
  • Speichern (const char* file);
  • GetBody

Damit Sie Ihre Bibliothek wie folgt nutzen können:

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");

Was uns die folgenden Schnittstellen gibt:

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

Jetzt müssen Sie nur noch die Lücken von hier aus ausfüllen 🙂

Glauben Sie mir, wenn ich das sage – wenn Sie Ihre Zeit investieren, um zu lernen, wie man Bibliotheken erstellt, insbesondere solche, die sich mit dem Laden, Manipulieren und Speichern von Daten befassen, werden Sie nicht nur von der Existenz solcher Bibliotheken abhängig sein, sondern Sie auch zu einem All- um bessere Programmierer.

🙂

BEARBEITEN

Ich weiß nicht, wie viel Sie bereits über String-Manipulation und -Parsing wissen; Wenn Sie also nicht weiterkommen, helfe ich Ihnen gerne weiter.

  • Alter, übertrieben. Danke eine Megatonne.

    – zkwentz

    6. Januar 2009 um 5:22 Uhr

  • Nein, nicht selbst machen. Verwenden Sie eine gut getestete Bibliothek.

    – Brian

    25. Februar 2010 um 20:58 Uhr

Hier ist ein Code, den Sie verwenden können. Die Daten aus der CSV-Datei werden in einem Array von Zeilen gespeichert. Jede Zeile ist ein Array von Strings. Hoffe das hilft.

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

  • Alter, übertrieben. Danke eine Megatonne.

    – zkwentz

    6. Januar 2009 um 5:22 Uhr

  • Nein, nicht selbst machen. Verwenden Sie eine gut getestete Bibliothek.

    – Brian

    25. Februar 2010 um 20:58 Uhr

1646356209 155 Wie kann ich CSV Dateidaten in C lesen und bearbeiten duplicate
stefanB

Verwenden von Boost-Tokenizer zum Analysieren von Datensätzen, siehe hier für weitere Details.

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

  • Übrigens, der escaped_list_separator analysiert eine Obermenge des csv-Formats, also sollten Sie mit allen ‘Eckfällen’ vertraut sein, boost.org/doc/libs/1_42_0/libs/tokenizer/…

    – stefanB

    25. Februar 2010 um 22:25 Uhr

929370cookie-checkWie kann ich CSV-Dateidaten in C++ lesen und bearbeiten? [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy