wie nutze ich eof() mit einem ifstream-Objekt?



  • Hallo miteinander.

    Ich will lediglich eine Textdatei wie folgt einlesen, bis ihr Ende erreicht ist:

    ifstream diffDatei;
    char	 buffer[MAX_CHAR];
    
    diffDatei.open("DIFF-T-TEST-LIVE.txt");
    if(diffDatei.is_open())
    {
        while(diffDatei.eof())
        {
            diffDatei.getline(buffer, MAX_CHAR);
            ...
    

    Allerdings liest mein Programm immer weiter. Wenn ich die Zeilen ausgeben lasse, dann erscheint nach dem eigentlichen Dateiende nix mehr auf dem Bildschirm, die Schleife läuft aber weiter. Habe die Prüfung erstmal auf

    while(diffDatei.good())
    

    geändert, aber warum funktioniert das mit eof() nicht?

    Gruß
    Kai



  • Hallo Kai,

    da gibt es eine ganz einfache Regel, die gilt bei Streams und die gilt auch bei allen sonstigen Funktionsaufrufen.
    ZUERST rufst Du eine Funktion auf, und DANACH prüfst Du ob ein Fehler aufgetreten ist oder sonst was.

    Also erst

    diffDatei.getline(buffer, MAX_CHAR);
    

    und danach

    if( diffDatei.fail() ) {
            // Huston wir haben ein Problem
            if( diffDatei.eof() ) {
                // nö, wir haben bloss das Ende der Datei erreicht
    

    .. Du bist nicht der erste, der das so machen will. Beispiele für erst auf EOF oder good() prüfen und dann lesen, gibt es zu Hauf' im I-Net. Aber deshalb ist es trotzdem falsch.

    Man kann das auch schön zusammen fassen:

    for( char buffer[MAX_CHAR]; diffDatei.getline(buffer, MAX_CHAR); ) {
            // hier buffer auswerten
            ;
        }
        if( !diffDatei.eof() ) {
            // da ist ein Problem aufgetreten, was nichts mit Ende-der-Datei zu tun hat
    

    BTW.: was willst Du eigentlich lesen? Dein Code schaufelt lediglich die Bytes aus der Datei in den Speicher.

    Gruß
    Werner



  • Hallo Werner.

    Danke für deine schnelle Antwort. Das leuchtet dann auch ein, wenn man es mal so gut dargestellt sieht.

    Was ich mit dem Code bezwecke? Ich muss eine Datei Zeile-für-Zeile einlesen und parsen, um den in der Datei beschriebenen Zustand ggf. bildlich darstellen zu können.

    Habe den char-Buffer vorhin mal durch einen std::string ersetzt, damit ich das Durchsuchen von Zeilen mit string-Funktionen erledigen kann - wurde tierisch langsam, dass Programm.

    Gruß
    Kai



  • Hallo Kai,

    _Bongo schrieb:

    Was ich mit dem Code bezwecke? Ich muss eine Datei Zeile-für-Zeile einlesen und parsen, um den in der Datei beschriebenen Zustand ggf. bildlich darstellen zu können.

    Habe den char-Buffer vorhin mal durch einen std::string ersetzt, damit ich das Durchsuchen von Zeilen mit string-Funktionen erledigen kann - wurde tierisch langsam, dass Programm.

    was hältst Du davon, den Stream gleich beim Einlesen zu parsen. Viele machen das mit string-Funktionen (die dafür nicht gemacht sind!), weil sie nicht wissen, wie das mit std::istream geht.

    Wie ist denn das Format Deiner Datei? Kannst Du die ersten paar Zeilen mal hier einstellen?

    Gruß
    Werner



  • OBJECT Modification "Init-Tabelle"(Table 50003)
    {
      OBJECT-PROPERTIES
      {
        Date=29.07.13;
        Time=16:00:39;
    

    Aus der ersten Zeile lese ich z.B. den Namen des Objekts, den Typ und die ID aus.



  • Werner Salomon schrieb:

    was hältst Du davon, den Stream gleich beim Einlesen zu parsen. Viele machen das mit string-Funktionen (die dafür nicht gemacht sind!), weil sie nicht wissen, wie das mit std::istream geht.

    Ich find die C++ IStreams so geil dafür, weil da ein Parser drin ist sozusagen.

    In Java muss ich mir jedesmal sod ermaßen einen abbrechen, dass es doch meistens einfach ist das Ganze über Strings zu machen, was dann antürlich ultra kompliziert ist und total fehleranfällig, jedoch bei dem Vorteil dass es dann auch niemand mehr versteht 😉



  • Skym0sh0 schrieb:

    Werner Salomon schrieb:

    was hältst Du davon, den Stream gleich beim Einlesen zu parsen. Viele machen das mit string-Funktionen (die dafür nicht gemacht sind!), weil sie nicht wissen, wie das mit std::istream geht.

    Ich find die C++ IStreams so geil dafür, weil da ein Parser drin ist sozusagen.

    In Java muss ich mir jedesmal sod ermaßen einen abbrechen, dass es doch meistens einfach ist das Ganze über Strings zu machen, was dann antürlich ultra kompliziert ist und total fehleranfällig, jedoch bei dem Vorteil dass es dann auch niemand mehr versteht 😉

    Zwar OT, aber ich halte das Interface der C++-Streams zum Parsen für extrem unintuitiv und umständlich. Der ganze Facet/Locale-Boilerplate für winzige Einstellungen nervt enorm.



  • Jodocus schrieb:

    Zwar OT, aber ich halte das Interface der C++-Streams zum Parsen für extrem unintuitiv und umständlich. Der ganze Facet/Locale-Boilerplate für winzige Einstellungen nervt enorm.

    Facets und Locales hab ich noch nie bei einem Parser gebraucht.



  • _Bongo schrieb:

    OBJECT Modification "Init-Tabelle"(Table 50003)
    {
      OBJECT-PROPERTIES
      {
        Date=29.07.13;
        Time=16:00:39;
    

    Aus der ersten Zeile lese ich z.B. den Namen des Objekts, den Typ und die ID aus.

    .. und das willst Du zeilenweise lesen und mit string-Funktionen zerpflücken? Bricht man sich da beim Codieren nicht die Finger?

    Ich würde mir das im Prinzip etwa so vorstellen. Ich gehe dabei davon aus, dass alle offenen '{' mit '}' wieder geschlossen werden. (Die Typ-Namen RDR und All habe ich willkürlich gewählt.)

    #include <cassert>
    #include <fstream>
    #include <iostream>
    #include <map>
    #include <string>
    
    template< char C >
    std::istream& Char( std::istream& in )
    {
        char c;
        if( in >> c && c != C )
            in.setstate( std::ios_base::failbit );
        return in;
    }
    
    template< char OpenC, char CloseC >
    struct RDR // liest einen String der mit den Zeichen OpenC und CloseC eingeschlossen ist
    {
        RDR( std::string& target )
            : m_target( target )
        {}
    
        friend std::istream& operator>>( std::istream& in, RDR xx )
        {
            return getline( in >> Char<OpenC>, xx.m_target, CloseC );
        }
    private:
        std::string& m_target;
    };
    
    class All
    {
    public:
        friend std::istream& operator>>( std::istream& in, All& rdr )
        {
            using namespace std;
            string token;
            if( in >> token )
            {
                if( token == "OBJECT" )
                {
                    string typ, name, id;
                    if( in >> typ >> RDR<'"','"'>( name ) >> RDR<'(',')'>( id ) )
                    {
                        clog << "Objekt Typ=" << typ << " Name=" << name << " Id=" << id << endl; // nur zur Demo
                        in >> Char<'{'> >> rdr >> Char<'}'>; // rekursiv weiter lesen!
                    }
                }
                else if( token == "OBJECT-PROPERTIES" )
                {
                    in >> Char<'{'>;
                    map< string, string > properties;
                    char c;
                    for( string key, value
                            ; in >> c && c != '}' && getline( getline( in.putback(c) >> ws, key, '=' ) >> ws, value, ';' ); )
                        properties.emplace( std::move(key), std::move(value) );
                    clog << properties.size() << " Properties gelesen" << endl; // nur Demo
                }
                else // hier weitere 'Objekte' anfügen
                {
                    cerr << "unbekanntes Token: " << token << endl;
                    in.setstate( ios_base::failbit );
                }
            }
            return in;
        }
    };
    
    int main()
    {
        using namespace std;
        ifstream in("DIFF-T-TEST-LIVE.txt");
        assert( in.is_open() );
        All rdr;
        if( in >> rdr )
            clog << "Ok " << endl;
    }
    

    Probiere das mal aus. Bin gespannt auf Dein Feedback.

    Gruß
    Werner



  • Danke dir. Der Code sieht echt sehr übersichtlich aus. So sehr bin ich allerdings nicht in die Parse-Materie, Streamverarbeitung, usw. vertieft. Versuche mal durch den Code durchzusteigen.

    Gruß
    Kai


Anmelden zum Antworten