chars aus Binary File einlesen - EOF wird nicht gesetzt [gelößt und erklärt]



  • Hallo,
    ich muss eine Datei einlesen (selbst erstellt in anderem Programmteil), die
    einfach nur char Werte enthält. Öffne ich die Datei bspw. im Editor werden die
    Chars korrekt angezeigt. Schaue ich mir im Debugmodus den Inhalt des ifstream buffers an,
    enthält er die gewünschten Werte. Von dieser Seite müsste eigentlich alles in Ordnung sein.
    Leider stürzt das Programm aber beim Einlesen dieser Datei ab, weil es die Schleife zum Beenden des Einlesevorgangs nicht verlässt.

    Ich habe lange gesucht und Bücher Internet und das Forum befragt, aber sehe den Fehler einfach nicht.
    Es wäre eine super Sache, wenn irgendjemand mir weiterhelfen könnte. Danke

    Mein Code sieht wie folgt aus

    namespace boost::filesystem = fs;
    
    list<char> ReadFile ( const fs::path filePath ){
       fs::basic_ifstream<char> fileStream( filePath, ios::in | ios::binary );
       // Throw exceptions in case badbit or failbit is set
       fileStream.exceptions( ios_base::badbit | ios_base::failbit );
       list<char> returnList;
    
       while (!fileStream.eof())
       {
          char c;
          // the program is aborted here when it tries get() after all chars of the file have been read
          // instead it should throw an exception or even better - end the loop
          if (fileStream.get( c ).fail() == false)
              returnList.push_back( c );
       }
    return returnList;
    }
    

    und hier der Aufruf der Methode

    try{
    list< char > charList = ReadFile( filePath );
    }
    catch( const ios_base::failure& e)
    {
    /// irgendwas
    }
    catch( const exception& e)
    {
    /// irgendwas
    }
    

    Ich habe mehrere Probleme:

    • EOF wird nicht gesetzt. Die Testdatei enthält 6 char Einträge, und ich kann im Debugmodus die Schleife
      auch genau 6 mal betreten, beim 7ten Leseversuch stürzt das Programm ab
    • es werden keine Exceptions geworfen
    • auch wenn ich ios_base::eof zu den gewünschten Exceptions hinzufüge wird keine Exception geworfen.

    Hat irgendjemand vielleicht eine Idee woran das liegen könnte ?

    Danke schonmal...



  • ich korrigieren mich:

    Setzte ich die Schleife direkt in einen Try Catch Block
    wird eine exception geworden
    ( ich habe auch versucht boost::filesystem::filesystem_error exceptions zu catchen)

    mit dem Code

    catch( const ios_base::failure& e){
            std::cout << "type: " << typeid(e).name() << std::endl;
            std::cout << "message: " << e.what() << std::endl;
    }
    

    gibt sie folgendes von sich preis:

    type: NSt8ios_base7failureE
    message: basic_ios::clear

    Das hilft mir aber leider nicht dabei weiter, zu verstehen was an meinem Code
    falsch ist...



  • Nach einiger Testerei hier die Erklärung für das Verhalten:

    der Befehl

    // Werfe eine Exception sobald eines der Flags gesetzt wird
    fileStream.exceptions( ios_base::badbit | ios_base::failbit  );
    try{
            while (!fileStream.eof())
            {
                char c;
                // get( c ) setzt das Failbit wenn kein Zeichen mehr gelesen werden kann und returned EOF
                // sobald das Failbit gesetzt ist, wird die Exception geworfen und die Schleife verlassen
                if ( (fileStream.get( c ).fail() ) == false)
                    content.push_back( c );
            }
        }
        catch( const ios_base::failure& e){
            std::cout << "type: " << typeid(e).name() << std::endl;
            std::cout << "message: " << e.what() << std::endl;
        }
    

    Sofern mit Exceptions gearbeitet wird macht das die While Schleife überflüssig

    Lässt man die Exceptions ausgeschaltet ist der Folgende Code korrekt

    while (!fileStream.eof())
       {
          char c;
          // Versuche das nächste Zeichen als char einzulesen. Tritt hierbei kein Fehler auf füge es zur Liste hinzu.
          // Kann kein weiteres Zeichen gelesen werden wird das Failbit und EOF gesetzt
          // beim nächsten Durchlauf der While Schleife wird die Eingangs-Bedinung nicht 
          // mehr erfüllt und der Einlesevorgang beendet
          if ( (fileStream.get( c ).fail() ) == false)
                    content.push_back( c );        
            }
        }
    

    Fazit:

    • Wenn man mit Exceptions arbeitet ist eine While Schleife zur Abfrage des EOF Bits überflüssig,
      weil die Exception geworfen wird sobald das Bit gesetzt wird.
    • Es wird bei jedesmal eine Exception geworfen, sobald das Ende einer Datei erreicht ist, wenn man
    .exceptions( ios_base::failbit );
    

    setzt.
    ( Failbit gesetzt bedeutet: nächste Operation geht schief )

    • Es empfiehlt sich, nur eine Exception zu werfen, wenn das badbit gesetzt ist,
    .exceptions( ios_base::badbit );
    

    weil auf diese Weise nur im wirklichen Fehlerfall Exceptions geworfen werden, und ansonsten ´
    die oben gezeigte Schleife sich um das Einlesen bis zum Dateieinde kümmert.
    ( Badbit gesetzt bedeutet: Stream ist nicht mehr verwendbar )

    • Wenn man ohne Exceptions arbeitet kann man das Failbit benutzen um zu überprüfen, ob ein Zeichen
      korrekt eingelesen wurde, und eine While Schleife die EOF abfragt, um das Dateiende zu finden

    Vielleichts hilfts ja irgendjemand mal weiter 😉

    Gruß
    zitroneneis


Anmelden zum Antworten