Arbeiten mit 2 CSV Dateien



  • So, ich beschäftige mich gerade mit CSV Dateien und hab da 1,2 Probleme...

    Grundlegend worauf ich hinaus will: Ich öffne eine CSV Datei, lese mir da Parameter aus, mache mit denen Rechnungen und schreibe sie dann in CSV Datei Nummer 2.

    Problem1:
    Eigentlich mehr ein "halbes" Problem, da es funktioniert, meine CSV Datei Nummer 1 sieht wie folgt aus:
    time, var1, var2, var3
    0.1, xx, xx, xx
    0.5, xx, xx, xx
    1, xx, xx, xx

    Ich will zum einen die Variablenleiste oben auslesen (funktioniert und ich denke auch ganz effizient) und ich möchte die "time" Spalte auslesen. Zur Zeit mache ich es so (Code hänge ich gleich), dass ich die Zeile als String auslese, alles wegschneide was nicht hingehört, das ganze in eine Double umwandeln und dann in einem Vektor speicher. Da das aber durchaus mal 1500 Variablen sein können Bau ich gerade quasi eine Bäckerei obwohl ich nur ein Brötchen haben will... Frage ist also ob das nicht irgendwie effizienter geht, da ich schon gemerkt habe, dass das doch ein bisschen Zeit frisst.

    while(csv1)
    					{	
    						std::getline(csv1, readhelp);
    						std::size_t found = readhelp.find(";");
    						if (found!=std::string::npos) readhelp.erase(found,readhelp.length());
    						else
    						{
    							std::size_t found = readhelp.find(","); 
    							readhelp.erase(found,readhelp.length());
    						}
    						boost::trim(readhelp);
    
    						try
    						{
    							doublehelp = boost::lexical_cast<double>(readhelp);
    						}
    						catch (boost::bad_lexical_cast const&)
    						{
    							doublehelp = 0;
    						}
    						timestepvector.push_back (doublehelp);
    						anz_timesteps++;
    					}
    

    Nummer 2 laufe ich gerade auf ein Problem auf wo ich nicht genau weiß woran es liegt, deswegen wird das jetzt leider etwas unspezifisch, vielleicht kann mir ja trotzdem jemand helfen...

    ich will ja erst CSV Datei 1 öffnen um dann entsprechend die Infos auszulesen. Dann will ich die CSV Datei 2 erstellen um da alles reinzuschreiben. Das ganze funktioniert jeweils für sich auch gut, aber wenn ich das zusammenpacke schreibt er mir die CSV Datei 2 nicht mehr, erst wieder, wenn ich das einlesen der ersten Datei auskommentiere. Mal so die Elementaren Schritte die ich mit den Dateien mache, vielleicht kann mir ja jemand sagen was fehlt (oder wo noch mehr Input benötigt ist).

    std::ifstream csv1;
    csv1.imbue(std::locale(""));
    csv1.open(ref_csvfile, std::ios::in);
    csv1.close();
    
    std::ofstream myfile;
    myfile.imbue(std::locale(""));
    myfile.open(outputfile);
    myfile.close();
    

    Das myfile.open funktioniert wie gesagt wunderbar, solange ich das ganze csv1 gekröse weglasse...



  • Habe Dein Problem nur kurz überflogen und Dir mal schnell folgenden Ansatz zusammengeschrieben. Sollte so in etwa auch compilieren, habs aber nicht getestet. Vielleicht hilfts Dir.

    Gruss

    std::ifstream ifs("input.csv");
    if (ifs.fail()) {
      // error
    }
    
    // Iterate tokens
    std::string in;
    std::vector<std::string> input;
    while (!getline(ifs, in).eof()) {
      boost::algorithm::trim(in);
      if (in.empty()) {
        continue;
      }
    
      input.push_back(in);
    }
    
    std::ofstream ofs("output.csv");
    if (ofs.fail()) {
      // error
    }
    
    std::vector<std::string> output;
    // do something with output...
    
    for (auto &out : output) {
      ofs << out << ";" << "\n";
    }
    


  • Ynnead schrieb:

    ... Frage ist also ob das nicht irgendwie effizienter geht, da ich schon gemerkt habe, dass das doch ein bisschen Zeit frisst.

    while(csv1)
    					{	
    						std::getline(csv1, readhelp);
    						std::size_t found = readhelp.find(";");
    						if (found!=std::string::npos) readhelp.erase(found,readhelp.length());
    						else
    						{
    							std::size_t found = readhelp.find(","); 
    							readhelp.erase(found,readhelp.length());
    						}
    						boost::trim(readhelp);
    
    						try
    						{
    							doublehelp = boost::lexical_cast<double>(readhelp);
    						}
    						catch (boost::bad_lexical_cast const&)
    						{
    							doublehelp = 0;
    						}
    						timestepvector.push_back (doublehelp);
    						anz_timesteps++;
    					}
    

    es geht vor allem sehr viel einfacher und ohne boost-Hilfe

    for( double doublehelp; csv1 >> doublehelp; csv1 >> skipline, ++anz_timesteps )
            timestepvector.push_back (doublehelp);
    

    skipline sieht so aus:

    std::istream& skipline( std::istream& in )
    {
        return in.ignore( std::numeric_limits< std::streamsize >::max(), '\n' ); // erfordert #include <limits>
    }
    

    sei noch der Unterschied bemerkt, dass die for-Schleife bei einem Lesefehler des 'double' beendet wird - Deine Lösung dagegen nicht. Ersteres finde ich dem Problem aber eher angemessen.

    Tomahawk schrieb:

    .. mal schnell folgenden Ansatz zusammengeschrieben.

    // ...
    while (!getline(ifs, in).eof()) {
      // bearbeite 'in'
    

    Ja - man findet derartige Codeschnipsel tausendfach im Internet. Trotzdem ist es falsch bzw. fehlerhaft.
    Bei einem fatalen Lesefehler (badbit) würde das in einer Endlosschleife enden, da ifs nie nach EOF geht und die letzte Zeile würde nie gelesen werden, wenn sie nicht mit einem Linefeed beendet ist.

    Zu dem 2.Problem fällt mir so nichts ein. Ich würde Dir empfehlen, nach dem Öffnen einer Datei in jedem Fall mit is_open abzufragen, ob alles Ok ist.

    Gruß
    Werner



  • O.k., das ist wirklich deutlich einfacher... Danke schonmal dafür 🙂

    Mit den Datein ist halt ein großes Problem vor allem weil ich überhaupt nicht weiß woran es liegt... Das Problem ist, alles was ich bisher an Dokumentation zum Arbeiten mit Dateien gefunden habe ist immer genau eine Datei, mir würde da ja auch schonmal helfen wenn irgendwo mal mehrere beschrieben sind ob man da auf irgendwas spezielles noch achten muss...



  • Ynnead schrieb:

    Mit den Datein ist halt ein großes Problem vor allem weil ich überhaupt nicht weiß woran es liegt... Das Problem ist, alles was ich bisher an Dokumentation zum Arbeiten mit Dateien gefunden habe ist immer genau eine Datei, mir würde da ja auch schonmal helfen wenn irgendwo mal mehrere beschrieben sind ob man da auf irgendwas spezielles noch achten muss...

    Grundsätzlich macht man bei mehr als einer Datei alles nur mehrfach. D.h. wenn Du weißt, wie man mit einer Datei umgeht, so kannst Du das einfach vervielfachen. Das sollte dann keine Seiteneffekte haben, solange Du eine Datei immer nur genau mit einem i/ofstream -Objekt bearbeitest!

    Bisher hast Du auch nicht gesagt, was genau 'nicht funktioniert'. Ist die Datei vorhanden? Ist sie leer? War sie vorher schon da? Ist sie schreibgeschützt? Was steht drin und was erwartest Du was da drin stehen sollte?
    Füge in jedem Fall die Abfrage mit is_open ein.

    Bleibt mir noch die Frage, ob es möglich wäre, die Dateien auch gleichzeitig zu bearbeiten? Kannst Du den Wert, den Du aus der einen Datei liest, nicht sofort in die Zieldatei schreiben ohne ihn in einem vector zwischen zu speichern?



  • Gleichzeitig lesen und schreiben geht nicht, ich lese Inputwerte für eine größere Rechnung aus (die dauert auch etwas) und schreibe dann die Ergebnisse der Rechnung in die zweite csv.

    Die zweite csv Datei ist vorher nicht da und soll mir vom Programm erstellt werden.

    Wird sie aber nicht, ABER wenn ich die Zeile

    my_csv_file.open(ref_csvfile, std::ios::in);
    

    auskommentiere wird mir danach auch von myfile.open(outputfile); anstandslos die Datei erstellt. Und bevor die Vermutung aufkommt, die Variable "outputfile" wird vor dem einlesen der csv schon komplett fertig generiert und auch im Programm dann nicht weiter angefasst bis zu dem myfile.open...

    Ich bekomme auch in beiden Fällen keine Fehlermeldungen beim Kompilieren (VS 2010) oder im Terminal, die Datei ist dann halt einfach nicht da. Deswegen kann ich dazu halt auch grad so wenig sagen, weil es so aussieht, als wenn alles reibungslos klappen würde, mit der Ausname, dass die Datei nicht erzeugt wird...

    Die erste Datei wird übrigens auch korrekt geöffnet (auslesen klappt auch anstandslos).


  • Mod

    Dann entweder selber debuggen oder uns ein vollständiges Minimalbeispiel zeigen, mit dem man den Fehler reproduzieren kann. Siehe dritter Link in meiner Signatur.



  • Jetzt beim erstellen des Minimalbeispiels hab ich festgestellt, dass es doch so funktioniert wie ich mir das vorstelle, nur bei mir dann irgendwo nen Bug drin ist... ich versuch dann erstmal selber den Fehler zu finden, ansonsten meld ich mich nochmal 🙂


Anmelden zum Antworten