Textfile lesen



  • Hallo,

    ich versuche eine Textdatei mit 8 Spalten zu lesen und wollte mit dem printf einer bestimmten Spalte überprüfen ob der Output richtig ist. Nun zeigt mir der Output nicht alles an.

    ifstream in("results_DYPbPb_eppspdf_noresumbutkt_ptbins_mu1.txt");
    std::string  str;
    while(getline(in,str)){
     if(str.find("#") < str.length()) continue;  // Line commented out
     if(str.length() == 0) continue;
     in >> m_low;
     in >> m_high;
     in >> y_low;
     in >> y_high;
     in >> pt_low;
     in >> pt_high;
     in >> yield;
     in >> uncertainty;
     printf("%f\n",yield);
    }
    
    

    Anbei ein Ausschnitt meiner Textdatei:
    #q2lo q2hi ylo yhi qTlo qThi PDF0 uncertainty
    2 2.25 0 1 0 0.25 7202.725044626975 435.4318337938282
    2 2.25 0 1 0.25 0.5 21567.39271231694 8.327705504918685
    2 2.25 0 1 0.5 0.75 32708.82699214583 7.284791733267677
    2 2.25 0 1 0.75 1 39710.17972304837 37.29963122991295
    2 2.25 0 1 1 1.25 42674.50401093271 8.01418863144115

    Als Output bekomme ich, wenn ich beispielsweise die Spalte "yield" ausgeben lasse:
    21567.392712
    39710.179723
    39710.179723

    Kann mir jemand hier dabei helfen?

    Vielen Dank

    Zafar



  • Die Standardformatierung bei printf verwendet nur 6 Nachkommazahlen für %f.
    Mit "%.16f" kannst du das maximieren (sofern du double, und nicht float, für yield verwendest).

    Für C++ solltest du aber besser cout verwenden:

    cout << setprecision(16) << yield << '\n'; // #include <iomanip> vorher einbinden
    

    PS: Du kannst aber nicht erwarten, daß jede Zahl bis auf die letzte Stelle exakt in eine double-Variable einlesbar ist (da die gesamte Präzision, Vor- und Nachkommastellen, nur ca. 15-16 Stellen umfasst: Doppelte Genauigkeit).



  • @Th69 sagte in Textfile lesen:

    Für C++ solltest du aber besser cout verwenden:

    Hm... ich emfinde gerade das Formatieren von Zahlen mit streams als EXTREM umständlich und vor allem unleserlich. Fängt bei der Präzision schon an: habe ich jetzt 16 signifikante Ziffern? Oder 16 Nachkommastellen? Ach was, da fehlt dann noch std::fixed usw. Und was, wenn man es mal wieder auf "defaults wie vorher" zurückstellen will?

    Ich würde daher inzwischen immer https://github.com/fmtlib/fmt empfehlen.



  • Also selbst mit:

    cout << setprecision(16) << yield << '\n';
    

    bekomme ich den gleichen Output, nur halt mit mehr Stellen.
    21567.39271231694
    39710.17972304837
    39710.17972304837

    Aber zum Beispiel der Wert 7202.725044626975 (2. Zeile in dem Ausschnitt der Textdatei) sollte auch im Output da sein.

    Für meine Variablen benutze ich double



  • @Zafar Du liest eine Zeile mit getline. Die ist dann nicht mehr im Stream. Dann liest du die werte aus dem Stream. Deshalb verlierst du jede 2te Zeile.



  • @Mittagspause Ah ok verstehe, was kann man dagegen tun?



  • @Zafar Du könntest mit deinen string einen stringstream initialisieren und die werte dann daraus so lesen, wie du das jetzt mit dem filestream machst. Kommt mir zwar ein bischen komisch vor ...



  • Wie wärs mit sowas - nur ein getline, wenn ein Fehler auftritt:

    #include <fstream>
    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        ifstream in("data.txt");
    
        double m_low, m_high, y_low, y_high, pt_low, pt_high, yield, uncertainty;
        std::string str;
    
        std::streampos in_pos;
        while (in) {
            in_pos = in.tellg();
            if (in >> m_low >> m_high >> y_low >> y_high >> pt_low >> pt_high >> yield >>
                uncertainty && in.peek() == '\n') {
                printf("Found entry, yield is %f\n", yield);
            } else {
                in.clear();
                in.seekg(in_pos);
                std::string s;
                if (getline(in, s)) {
                    if (s.empty() || s.find("#") != std::string::npos) {
                        // ok, empty or comment (# irgendwo in Zeile, für am Anfang whitespace skippen)
                    } else {
                        cout << "Error in line: " << s << "\n";
                    }
                }
            }
        }
    }
    


  • @wob , danke dir!
    Ich habe das angewendet auf einer Textdatei die mehr als 10000 Zeilen hat und bei diesem Fall werden einige Zeilen nicht ausgegeben. Da werden ersten 100 Zeilen komplett ignoriert. Ich weiß nicht ob es an der Zeilenanzahl abhängt



  • @Zafar sagte in Textfile lesen:

    Da werden ersten 100 Zeilen komplett ignoriert. Ich weiß nicht ob es an der Zeilenanzahl abhängt

    Ich behaupte mal: kann nicht sein. Irgendwas stimmt da nicht. Du hast aber nicht zufällig "#" in den ersten 100 Zeilen drin? Ansonsten sollte das Programm doch auch Zeilen ausgeben, wenn es die nicht lesen kann. Man könnte am Ende nochmal testen, ob man wirklich eof erreicht hat oder ob andere Fehler vorliegen (generell geht mehr Fehlerkontrolle bestimmt), aber dass die ersten 100 Zeilen grundlos überlesen werden, ist nicht zu glauben. Wobei: das Programm hat möglicherweise Probleme, wenn die Anzahl der Felder pro Zeile nicht stimmt, da beim in >> auch Zeilenumbrüche überlesen werden können. Aber wenn dir Datei korrekt ist, liest das Programm korrekt, würde ich mal behaupten.



  • @wob Eigentlich hat nur die erste Zeile ein #. Ja das ist sehr komisch. Die hinteren Zeilen werden problemlos und ohne Lücken ausgegeben . Es geht hauptsächlich um die ersten hunderten von Zeilen.

    Ist es möglich hier diese Textdatei anzuhängen ?



  • @Zafar ich habe oben noch ein && in.peek() == '\n' ins if eingebaut, sodass "Zeilenende nach lezter Zahl" Pflicht wird.

    Ist es möglich hier diese Textdatei anzuhängen ?

    Kannst du nicht einfach testen, ob das Problem auch bei einer kleineren Testdatei auftritt, z.B. wenn du nur die ersten 20 Zeilen nimmst? Werden die dann auch übersprungen? Sieht die Textdatei ansonsten "normal" aus?



  • @wob sagte in Textfile lesen:

    Ich würde daher inzwischen immer https://github.com/fmtlib/fmt empfehlen.

    Man sollte vielleicht nicht unerwähnt lassen, dass die mittlerweile auch zum (C++20) Standard gehört: std::format.



  • This post is deleted!


  • @wob Ich habe die ersten 50 Zeilen genommen und es hat problemlos funktioniert. Nur bei mehr als 10000 Zeilen ignoriert er die ersten Zeilen, voll komisch.

    Das Output startet einfach ab Zeile 1279



  • @Zafar sagte in Textfile lesen:

    @wob Ich habe die ersten 50 Zeilen genommen und es hat problemlos funktioniert. Nur bei mehr als 10000 Zeilen ignoriert er die ersten Zeilen, voll komisch.

    Das Output startet einfach ab Zeile 1279

    Du machst etwas anderes falsch oder die Textdateien enthalten nicht das, was du denkst. Die Funktion weiß doch am Anfang noch gar nicht, wie viele Zeilen es geben wird.

    Wie sieht dein vollständiges Programm aus, woher weißt du, dass es die ersten Zeilen nicht korrekt einliest? Hinterfrage jedes Detail deiner Annahmen!

    (und zuletzt: bist du sicher, dass du C++ brauchst, geht nicht Python? Geht es um parton density functions von Blei-Blei und Muonen-Transversalimpuls? Wäre meine Vermutung anhand des Dateinamens...)



  • @wob Ich habe was ausprobiert, habe in der while Schreife einen counter eingebaut und dann diesen counter ausgeben lassen. Bei beispielsweise 500 Zeilen gibt der counter mir auch 500 an. Vielleicht liegt es daran, dass mein bash diese große Anzahl an Zeilen net komplett ausgeben kann. Ich benutze zur Info Linux.

    Ich benutze ein framework, das sich root nennt. das ist auf c++ basiert



  • Was hat bash jetzt damit zu tun?! (es gibt auch ein paar Commits von mir im ROOT-Source...)

    Rat: Nimm Python (ok, zumindest für soche Sache wie Einlesen)! ROOT hat doch wundervolle Python-Bindings.



  • @wob einfach den Code fürs Einlesen in python umwandeln?



  • Das ist nur ein genereller Rat. Weil solche Dinge in Python sehr viel einfacher sind. Aber du hast doch schon praktisch den ganzen Einlesecode. Ich kann nicht erraten, was bei dir falsch läuft.

    Liest du in einen TTree ein? Nutzt du RDataFrames?


Log in to reply