Aus .txt Datei lesen



  • durch das const werden alle membervariablen (in der jeweiligen methode) konstant (außer jene, die als mutable spezifiziert worden sind).
    getline erwartet allerdings als übergabeparameter eine referenz auf einen nicht-konstanten istream.

    vielleicht auch ein hinweis, die ifstream klasse nicht zu einem klassenmember zu machen 😉



  • Ja, mhm, aber es ist doch schon cooler und vom Stil besser, wenn ich die ifstream Klasse als Klassenmember mache. Wo soll ich die den sonst hin tun? Ich kann das ding ja nicht einfach "global" machen, wenn der Code mal noch wächst....is das doch schon mal n schlechter Untergrund?!
    Ich hätt das jetzt so gemacht:

    #include <iostream>
    #include <fstream>
    #include <string>
    using namespace std;
    
    class read
    {
        public:
        read(const string &file_name);
        inline bool error() const;
        bool readout() const;
    
        private:
        const ifstream m_file;
    };
    
    read::read(const string &file_name)
    :m_file(file_name.c_str())
    {
    
    }
    
    bool read::error() const
    {
        return !m_file;
    }
    
    bool read::readout() const
    {
        if(error()) return false;
        string buffer;
        const ifstream *temp_const=&m_file;
        ifstream *temp=const_cast<ifstream*>(temp_const);
        while(getline(*temp,buffer))
        {
            cout << buffer << "\n";
        }
        return m_file;
    }
    
    class write
    {
        public:
        write(const string &file_name);
        inline bool error() const;
        bool fill_in();
    
        private:
        ofstream m_file;
    
    };
    
    write::write(const string &file_name)
    :m_file(file_name.c_str())
    {
    
    }
    
    bool write::error() const
    {
        return !m_file;
    }
    
    bool write::fill_in()
    {
        if(error()) return false;
        string buffer;
        while(getline(cin,buffer))
        {
            if(buffer == "exit") return true;
            m_file << buffer << "\n";
        }
        return m_file;
    }
    
    int main()
    {
        read test("D:/test.txt");
        test.readout();
        return 0;
    }
    

    Ist "const_cast" hier fehl am Platz, weil dass soll ja auch schlechter Stil sein?
    Was schlagt ihr mir dann vor, wie mach ich dass dann am besten?
    Warum muss den bitte des blöde "getline" eine Referenz haben die nur nicht konstante Objekte nimmt?!
    Ma so nebenbei, wie mach ich des bitte, das ein Parameter konstante Objekte nicht annimmt?
    Mh ich könnte jetzt natürlich die "readout" Methode nicht const deklarieren, aber is ja auch schlechter Stil....was tun?!

    MfG
    Stromberg



  • Stromberg schrieb:

    Ist "const_cast" hier fehl am Platz, weil dass soll ja auch schlechter Stil sein?
    Was schlagt ihr mir dann vor, wie mach ich dass dann am besten?
    Warum muss den bitte des blöde "getline" eine Referenz haben die nur nicht konstante Objekte nimmt?!

    weil getline aus dem stream etwas ausliest und ihn daher verändert. der stream wird verändert, also darf er nicht konstant sein. ist doch ganz logisch 😉
    const_cast ist hier nicht nur schlechter stil, sondern provoziert undefiniertes verhalten, denn dein stream ist "tatsächlich" konstant. ich sage dir jetzt mal nicht die schuss-in-den-fuß lösung mit mutable, sondern rate dir dazu, den stream lokal in der funktion zu halten und dir stets genau zu überlegen, ob eine methode ihr objekt verändert oder nicht. wenn ja, dann darf sie eben nicht const sein.

    Ma so nebenbei, wie mach ich des bitte, das ein Parameter konstante Objekte nicht annimmt?

    du überlädst die funktion für konstante objekte und lässt sie undefiniert (wenn ich richtig verstanden habe, was du willst)

    Mh ich könnte jetzt natürlich die "readout" Methode nicht const deklarieren, aber is ja auch schlechter Stil....was tun?!

    const macht noch keinen guten stil. wie gesagt, es hängt von der semantik der methode ab. wenn sie was ändert, dann natürlich nicht const.



  • Was bedeutet den genau "undefiniertes Verhalten"?
    Es wäre aber doch auch nicht extrem schlechter Stil wenn ich die "readout" Methode einfach nicht const machen würde?
    Oder ich machs so wie dus gesagt hast:

    bool read::readout() const
    {
        ifstream file(m_file_name.c_str());
        if(!file) return false;
        string buffer;
        while(getline(file,buffer))
        {
            cout << buffer << "\n";
        }
        return file;
    }
    

    Is beser so oda?
    MfG
    Stromberg



  • Mh was ist eigentlich an "mutable" so schlecht, fällt mir grad auf???!
    MfG
    Stromberg



  • Noch was, "(D)Evil" schrieb:

    bool read::show(std::ostream& out) 
    { 
        if (error()) return false; 
    
        std::string buff; 
        while (std::getline(m_file, buff)) 
            out << buff << std::endl; 
    
        return m_file; 
    }
    

    dass müsste man dann doch wohl so anwenden oder:

    ....
    read test;
    test.show(std::cout);
    ....
    

    Und bei meiner Methode befindet sich das "cout" halt gleich in der Methode, also:

    ....
    cout << buf << "\n";
    ....
    

    Was ist jetzt besser\schneller? Oder ist es egal?

    MfG
    Stromberg



  • Hmm der Unterschied besteht viel mehr in der vielseitigeren Verwendungsmöglichkeit. Du kannst deine Ausgabe nur in std::cout Umleiten. Durch die Übergabe des Ausgabestreams an die Funktion kannst du bsw. auch in eine andere Datei umleiten.



  • (D)Evil schrieb:

    Hmm der Unterschied besteht viel mehr in der vielseitigeren Verwendungsmöglichkeit. Du kannst deine Ausgabe nur in std::cout Umleiten. Durch die Übergabe des Ausgabestreams an die Funktion kannst du bsw. auch in eine andere Datei umleiten.

    du kannst cout auch in eine datei umleiten, indem du dessen streambuf änderst 😉
    aber das wäre natürlich nicht so.. hm.. intuitiv.
    intuitiv wäre ein operator<< wohl am ehesten. aber das schlägt sich etwas mit dem konzept, das hinter dieser klasse zu stehen scheint. aber ob es so gut ist, ein objekt zu haben, dass mit dem namen "read" eher an eine funktion erinnert?

    Stromberg schrieb:

    Was bedeutet den genau "undefiniertes Verhalten"?

    darüber bist du noch nicht gestoßen? das bedeutet, dass dein compiler aus dem code alles mögliche machen kann. im schlimmsten fall lässt es kleine dämonen aus deiner nase springen.

    an mutable ist grundsätzlich nichts schlechtes (wenn man es richtig verwendet), aber du deklarierst deine funktion als "funktion, die nichts an der jeweiligen instanz ändert" und dann willst du deine membervariablen so spezifizieren (mit mutable), dass sie trotzdem geändert werden können? hebt die wirkung auf. verzichte auf const. (oder lagere den stream aus, was zusätzlich den vorteil bringt, dass deine klasse kopierbar wird.)



  • Hier is der Code nochma, bissel umgeändert, aufgeteilt und noch bissel verpackt....
    main.cpp

    #include "text_editor.hpp"
    
    int main()
    {
        text_editor program;
        while(program.menu());
    
        return 0;
    }
    

    text_editor.hpp

    #ifndef TEXT_EDITOR_HPP_INCLUDED
    #define TEXT_EDITOR_HPP_INCLUDED
    
    #include <iostream>
    #include <string>
    
    class read
    {
        public:
        read(const std::string &file_name_);
        bool readout(std::ostream &ios_object) const;
    
        private:
        const std::string m_file_name;
    };
    
    class write
    {
        public:
        write(const std::string &file_name_);
        bool fill_in(bool remove);
    
        private:
        const std::string m_file_name;
    
    };
    
    //Macht die Klassen "read" und "write" Benutzerfreundlicher
    class text_editor
    {
        public:
        text_editor();
        bool menu();
        bool handle_file_write() const;
        bool handle_file_read() const;
        void error_message(const std::string &message);
    
        private:
        bool m_remove;
    
    };
    
    #endif // TEXT_EDITOR_HPP_INCLUDED
    

    text_editor.cpp

    #include <iostream>
    #include <fstream>
    #include <conio.h>
    #include "text_editor.hpp"
    #include "ic.hpp" //Improved Konsole
    
    using namespace std;
    using namespace ic; //Improved Konsole
    
    //KLASSE READ
    read::read(const std::string &file_name_)
    :m_file_name(file_name_)
    {
    
    }
    
    //Methode um Datein auszulesen
    bool read::readout(ostream &ios_object) const
    {
        ifstream file(m_file_name.c_str()); //<-- Streamobjekt "file"
        if(!file) return false; //Stream fehlerhaft?
        if(!ios_object) return false; //Objekt Fehlerhaft?
        string buffer;
        while(getline(file,buffer))
        {
            ios_object << buffer << "\n";
        }
        //<-- Ab hier wird "file" false!!! Warum?
        file.clear(); //Kann das nur mit dem hier beheben, sonst wird text_editor::message_error() aufgerufen
                      //Aber ist ja auch bissel gemogelt wenn ich dann einfach alles wieder "clear()" mache.
                      //Aber was hat "file" hier für ein Problem?
        cout << file << endl;
        getch();
        return file;
    }
    
    //KLASSE WRITE
    write::write(const std::string &file_name_)
    :m_file_name(file_name_)
    {
    
    }
    
    bool write::fill_in(bool remove)
    {
        ofstream file;
        if(remove) file.open(m_file_name.c_str()); //Datei wird immer neu erstellt
        else file.open(m_file_name.c_str(), ios::out | ios::app); //In Datei weiter schreiben
    
        if (!file) return false;
        string buffer;
        while(getline(cin,buffer))
        {
            if(buffer == "exit") return true;
            file << buffer << "\n";
        }
        return file;
    }
    
    //KLASSE TEXT_EDITOR
    text_editor::text_editor()
    :m_remove(false)
    {
    }
    
    bool text_editor::menu()
    {
        short input;
        cout << "< 1 > Datei beschreiben\n";
        cout << "< 2 > Datei lesen\n";
        cout << "< 3 > Programm beenden\n";
    
        cout << "\n\n\n### OPTIONEN ###\n\n";
        cout << "< 4 > Beim beschreiben Datei immer neuerstellen";
        if(m_remove) cout << " 'AN'\n";
        else cout << " 'AUS'\n";
    
        cout << "\n\n\n--> ";
        cin >> input;
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(),'\n');
    
        //Bildschirm löschen | Cursor Poition nach oben
        con.clearColor(BG_BLACK);
        con.setCurPos(0,0);
    
        switch(input)
        {
            case 1:
            if(!handle_file_write()) error_message("Das Beschreiben musste beendet werden.\n");
            break;
            case 2:
            if(!handle_file_read()) error_message("Das Lesen musste beendet werden.\n") ;
            break;
            case 3:
            return false;
            break;
            case 4:
            if(m_remove) m_remove=false;
            else m_remove=true;
            break;
        }
    
        //Bildschirm löschen | Cursor Poition nach oben
        con.clearColor(BG_BLACK);
        con.setCurPos(0,0);
    
        return true;
    }
    
    bool text_editor::handle_file_write() const
    {
        string save_name;
        cout << "Dateiname: ";
        getline(cin,save_name);
        cout << "'exit' am Zeilenanfang + 'ENTER' = Schreibprogramm wird beendet\n\n";
        write t_e_write(save_name);
        return t_e_write.fill_in(m_remove);
    }
    
    bool text_editor::handle_file_read() const
    {
        string save_name;
        cout << "Dateiname: ";
        getline(cin,save_name);
        cout << "Beliebiger Tastendruck = Leseprogramm wird beendet\n\n";
        read t_e_read(save_name);
        return t_e_read.readout(cout);
    }
    
    //Fehlermeldung, wenn ein stream "false" zurückgibt
    void text_editor::error_message(const string &message)
    {
        //Bildschirm löschen | Cursor Poition nach oben
        con.clearColor(BG_BLACK);
        con.setCurPos(0,0);
    
        cout << "Ein Problem wurde festgestellt!\n";
        cout << message;
        getch();
    }
    

    Was haltet ihr davon?

    Hab noch ein Problem, meine Methode "readout" gibt immer "false" zurück, wodurch ein Error aufgerufen wird. Das liegt daran dass das Streamobjekt "file" plötzlich nach der while Schleife false ist, obwohls vorher noch true war....
    [siehe: text_editor.cpp, Zeile 29]
    Die Datei wird super eingelesen, alles...richtig aufm Bildschirm der Text ausgegeben...passt alles, nur das "file" dann "false" ist, und dadurch "false" von der Methode "readout" zurück gegeben wird, und dadurch wird wiederum die "Error Methode" aufgerufen!!!! Ich versteh aber einfach nicht warum diese verdammte Streamobjekt "false" wird?!!!
    Vll. blickt da eienr von euch besser durch.

    MfG
    Stromberg



  • Du liest in readout solange mit getline ein bis die false zurückliefert. Dies ist dann der Fall wenn nichts mehr gelesen werden kann, also am Dateiende. Da wird aber dann auch eof() gesetzt und file liefert somit false zurück.
    Die Lösung mit clear ist da schon ok evtl. kannst du ja noch den Filepointer auf den Anfang zurück setzten.



  • bool write::fill_in(bool remove)
    {
        ofstream file;
        if(remove) file.open(m_file_name.c_str()); //Datei wird immer neu erstellt
        else file.open(m_file_name.c_str(), ios::out | ios::app); //In Datei weiter schreiben
    
        if (!file) return false;
        string buffer;
        while(getline(cin,buffer))
        {
            if(buffer == "exit") return true;
            file << buffer << "\n";
        }
        return file;
    }
    

    nicht so perfekt 😉

    bool write::fill_in(std::istream& in = std::cin, bool empty = true)
    {
        std::ofstream file_stream(m_file_name.c_str(), empty == true ? std::ios::out : std::ios::app);
        if (!file_stream) return false;
    
        std::string buffer;
        while (std::getline(in, buffer) && buffer != "exit")
            file_stream << buffer << "\n";
    
        return file_stream;
    }
    

    ... bei std::ofstream ist standardmäßig std::ios::out drin. kannst es hier in dem Fall für den einfachen Vergleich aber misbrauchen 😉 Und die Schleife kannst du auch verkürzen (s. Code) und statt return true hättest du sonst auch lieber gucken sollen ob file_stream einen Fehler gefunden hat 😉

    //Methode um Datein auszulesen
    bool read::readout(std::ostream& out) const
    {
        if (!out) return false; // sonst wird hier noch das std::ifstream Objekt erzeugt! ...
    
        std::ifstream file_stream(m_file_name.c_str());
        if (!file_stream) return false;
    
        std::string buffer;
        while (std::getline(file_stream, buffer))
            out << buffer << "\n";
    
        return true;
    }
    


  • Heißt das hier:

    ...empty == true ? std::ios::out : std::ios::app);
    

    soviel wie "wenn empty true ist, dann setzte als Parameter "std::ios::out : std::ios::app", wenn nicht dann setz einfach nichts (also halt default Parameter)?
    Das sowas geht, wusste ich anfangs nicht, weil ich hab das erst so gemacht:

    if(remove) ofstream file(.....);
    else ofstream file(.....,.....);
    

    Aber is ja Unsinn, weil des wird ja nur innerhlab des if-Scope deklariert, und verliert außerhalb dann seine Wertigkeit.
    Und des halb hab ich das mit dem ".open"....gemacht..aber is ja alles schlecht, des von dir is natürlich um einiges besser.
    MfG
    Stromberg



  • nein, es bedeutet "wenn empty true ist, dann setze als parameter ios::out, andernfalls ios::app" (':' bedeutet andernfalls)

    abgesehen davon sollte man mit boolschen werten keine vergleiche machen (weil es ohne auch geht)



  • Ja, aber wie kann n das gehen, wenn empty "true" ist, dann wird "ios::out" gesetzt. Verstehe ich noch, aber wenn empty "false" ist, dann wird ja "ios::app" gesetzt, aber das muss doch immer "ios::out | ios::app" heißen, nicht nur "ios::app"?
    Wie nennt man n das eigentlich ":" und "?" Vergleichsoperatoren für Parameter oder was... hab davon igrendwie noch nie was mitbekommen 😞
    Hat jemand einen Link wo da noch bissel ins Detail gegangen wird, oder kann man da nich mehr viel ins Detail gehen?
    Also ich mein mit if kann ich schon umgehen....aber die dinger da hab ich irgendwien icht gekannt.
    MfG
    Stromberg



  • sollte es, ja.

    das "ding" ?: nennt sich der "ternäre operator", der einzige operator mit drei operanden, der außerdem nicht überladen werden kann.



  • Also setzte er dann noch "ios::out" automatisch zu "ios::app" dazu oder wie?
    MfG
    Stromberg



  • Naja du hast schon recht, theoretisch steht da bei empty == false nur ein std::ios_base::app. Doch da du einen std::ofstream gewählt hast, ist automatisch std::ios_base::out gesetzt 😉 Kannst auch empty == true ? 0 : std::ios_base::app nehmen, sollte auch gehen.



  • ja, so geht es auch. es funktioniert nur dann nicht mehr, wenn du den ofstream gegen einen fstream austauschst.


Anmelden zum Antworten