EOF-Charakter (Probleme mit std::fstream.eof() )



  • Scheint nicht zu funktionieren.... 😞

    was ich damit vorhatte:

    /// read the data
    void TextDatabase::read_data()
    {
    	ifstream file(filename.c_str());
    	if (!file) throw Error("unable to open database");
    	Book new_book;
    	while (file.peek() != '\026') // <<<<< hier kommts hin
    	{
    		file >> new_book;
    		booklist.push_back(new_book);
    	}
    }
    

    Ich wollte damit das Problem umgehen dass im Falle einer leeren Datei ein Datensatz (der dummerweise leer ist) eingelesen wird.

    Fuer alternative Loesungen dieses Problem waer ich dankbar 🙂



  • einfach

    while (!file.eof ())
    


  • randa schrieb:

    einfach

    while (!file.eof ())
    

    Nope, damit eben hab ich mein Problem...

    stell dir vor ich hab eine absolut leere Datei....

    d.h.

    while (!file.eof ())
    

    schlaegt im ersten Durchlauf nicht Alarm, obwohl kein Datensatz in im File steht...

    file >> new_book;
    

    liest dann einen leeren Datensatz ein



  • dann sollte die Datei auch keine leeren Stellen enthalten. Wozu auch so eine Datei?
    Oder halt

    while (!file.eof ())
    {
    	if (aktuellesZeichen==' ') continue;
    	//...
    }
    

    so in der Richtung.



  • Kein "leeres Zeichen", sondern gar kein Zeichen.... ehm....

    Beim allerersten Starten des Programmes wird eine leere Datei angelegt:

    /// Ctor
    TextDatabase::TextDatabase(const string& filename_)
    	: filename(filename_)
    {
    	try
    	{
    		read_data();
    	}
    	// if the file doesn't exist, an error will be thrown
    	// we simply create the file and try again :)
    	catch(TextDatabase::Error& error)
    	{
    		ofstream dummy(filename.c_str());
    		dummy.close();
    
    		// try again. If opening the file still doesn't work and
    		// read_data() throws again, then there's something really
    		// wrong. So let the caller catch the exception
    		read_data();
    	}
    }
    

    d.h. die Datei ist jetzt absolut leer. Da steht absolut gar nix, nada, niente drinnen...

    aber fstreams setzten das EOF-Bit bekanntlich ja erst, NACHDEM sie EOF eingelesen haben....

    d.h.

    wenn

    while (!file.eof())
    }
    

    auf eine leere Datei losgelassen wird, dann wird eine Iteration der while-Schleife durchlaufen. Denn erst sobald ich das allererste Zeichen aus der leeren Datei auslese, wird file.eof() true ergeben...

    (deshalb mein Gedanke, mit file.peek() zu sehen, ob nicht das erste Zeichen bereits EOF ist, nur dass ich kA habe, wie EOF aussieht 😃 )



  • Ich glaube, dein Problem liegt eher darin, wie die Datei angelegt wird.
    Du kannst die Datei mit ios::trunc öffnen, dann wird alles gelöscht und du schreibst gescheit rein. Oder du löschst das eof halt manuell.
    Und du kannst auch einfacher feststellen, ob die Datei von anfang an leer ist.

    Und die Datei wird ja nicht von dem Programm angelegt, sie muss bereits exisiteren. Also ist sie beim öffnen ja nicht zwangsläufig leer. Du sagst aber

    d.h. die Datei ist jetzt absolut leer. Da steht absolut gar nix, nada, niente drinnen...

    Und du erwartest ja nicht immer eine leere datei *g*



  • du missverstehst mich, und zwar grundlegend 😃

    Und die Datei wird ja nicht von dem Programm angelegt, sie muss bereits exisiteren.

    1. Ich erwarte keine leere Datei, aber beim ALLERALLERALLERALLERALLERERSTEN Start des Programmes (d.h. z. B. nach der Installation) gibts die Datei noch nicht, und wird deshalb sehr wohl vom Programm angelegt (siehe Ctor von TextDatabase, den ich geposted hab um das nochmal zu verdeutlichen).

    du kannst die Datei mit ios::trunc öffnen, dann wird alles gelöscht und du schreibst gescheit rein. Oder du löschst das eof halt manuell.

    2. das ganze soll eine Datenbank darstellen, d.h. ich will LESEN, nicht SCHREIBEN. (BTW: read_data() verwendet einen ifstream, da gibts kein ios::trunc 🙄 😉 ).

    Und du kannst auch einfacher feststellen, ob die Datei von anfang an leer ist.

    3. ja, aber das loest mein Problem nicht, naemlich:

    file.eof() wird erst gesetzt, _nachdem_ EOF eingelesen wird: vielleicht verdeutlicht folgender Pseudocode mein Problem:

    ich will eine Datei auslesen. also:

    1. Datei oeffnen
    2.    WENN (datei noch nicht EOF)   <===== gleich nach dem oeffnen nie der Fall
    3.        lies Datensatz ein
    4.        wieder zu 2.
    

    Aber gleich nach dem Oeffnen der Datei ist die Datei 100%ig nicht EOF. Eben weil ja eof() erst dann true ergibt, wenn das EOF-Zeichen eingelesen wurde. Und gleich nach dem Oeffnen der Datei ist das nicht moeglich, eben weil noch gar nichts eingelesen wurde.

    Das Teilproblem kann ich loesen, indem ich teste, ob die Dateigroesse > 0. Aber wenn ich genau 1 (oder n) Datensaetze in der Datei hab:

    beim 1. Durchgang funktioniert alles Problemlos, der Datensatz wird eingelesen, passt. Der Lesezeiger steht jetzt genau _vor_ dem EOF-Zeichen. Die Ueberpruefung "datei noch nicht am EOF" gibt also TRUE zurueck, das Programm versucht noch einen Datensatz einzulesen... (was aber nicht geht, weil ja nur noch EOF in der Datei steht)... und da liegt mein Problem 😞



  • Hi,

    warum liest du nicht einfach, prüfst dann mit eof() und pushst ihn erst danach, d.h. wenn eof() == false gilt, in den std::vector?

    ChrisM



  • ChrisM schrieb:

    warum liest du nicht einfach, prüfst dann mit eof() und pushst ihn erst danach, d.h. wenn eof() == false gilt, in den std::vector?

    Ist ein guter Vorschlag, ja 🙂

    Mir waer's nur lieber, ich koennt die Ueberpruefung in den Kopf der while-Schleife stecken. Ausserdem interessierts mich mittlerweile aus reiner Neugier: was ist das ASCII-Zeichen fuer EOF, wenn das ueberhaupt OS-uebergreifend immer das selbe ist?



  • du missverstehst mich, und zwar grundlegend

    Den Eindruck habe ich auch 😃

    und wird deshalb sehr wohl vom Programm angelegt

    Meines Wissens können die streams keine Dateien erzeugen, nur existierende öffnen. Kann sein das ich hier grob falsch liege.

    read_data() verwendet einen ifstream, da gibts kein ios::trunc

    Ich meinte ja auch beim "erzeugen" der Datei.

    Wie genau sich die eof-Erkennung verhält, weiß ich nicht so genau, aber wenn das stimmt was du sagst, würde sich die eof-Erkennung eigentlich falsch verhalten.
    Aber dein zugrundeliegendes Problem hab ich verstanden. Du müsstest also prüfen, ob der nächste Token ein eof ist.

    unsigned char EOF=26;
    while (!file.eof () && nächstesZeichen!=26)
    ...
    

    keine Ahnung ob das klappt.

    Edit: Ascii Tabelle

    Edit2: Äh, ja. Einfach vorher in einen Buffer lesen und auf gültigkeit checken wär wohl am einfachsten.



  • randa schrieb:

    und wird deshalb sehr wohl vom Programm angelegt

    Meines Wissens können die streams keine Dateien erzeugen, nur existierende öffnen. Kann sein das ich hier grob falsch liege.

    wenn du mit ofstream auf Dateien zugreifst, die noch nicht existieren wird versucht, die Datei anzulegen. Gibt aber ein ios-flag, um das zu verhindern 🙂

    read_data() verwendet einen ifstream, da gibts kein ios::trunc

    Ich meinte ja auch beim "erzeugen" der Datei.

    Wie genau sich die eof-Erkennung verhält, weiß ich nicht so genau, aber wenn das stimmt was du sagst, würde sich die eof-Erkennung eigentlich falsch verhalten.

    EOF wird erst nach dem Fileende gesetzt, das ist (leider?) so. Vielleicht hats ja wirklich einen Grund, ich kenn ihn nicht 😉

    Aber dein zugrundeliegendes Problem hab ich verstanden. Du müsstest also prüfen, ob der nächste Token ein eof ist.

    unsigned char EOF=26;
    while (!file.eof () && nächstesZeichen!=26)
    ...
    

    keine Ahnung ob das klappt.

    Genau sowas in der Art hatt ich gesucht, leider funktioniert das (zumindest mit 26) nicht 😞

    Edit2: Äh, ja. Einfach vorher in einen Buffer lesen und auf gültigkeit checken wär wohl am einfachsten.

    Jo, das mach ich jetzt 🙂



  • randa schrieb:

    "\026"
    

    glaub ich.

    Wie kommst du auf die Idee? EOF ist ein Makro das zu einem negativen Int-Wert expandiert.

    Ich wollte damit das Problem umgehen dass im Falle einer leeren Datei ein Datensatz (der dummerweise leer ist) eingelesen wird

    Die Lösung ist einfach:

    while (file >> new_book)
    {
        booklist.push_back(new_book); 
    }
    

    randa schrieb:

    einfach

    while (!file.eof ())
    

    Käse. Der Test auf !eof ist, wie ich in diesem Forum schon öfter geschrieben habe als die Sahara Sandkörner hat, in den allermeisten Fällen keine gute Schleifenbedingung.
    Das eof-Bit wird gesetzt, *nachdem* versucht wurde über das Dateiende hinaus zu lesen. Nicht vorher. Ein Stream kann nicht in die Zukunft schauen und kann deshalb nicht einfach mal so wissen, ob das Dateiende erreicht wurde. Erst kommt der Versuch etwas zu lesen. Dann kommt das "Mööp! Datei zu ende" und dann wird das eof-Bit gesetzt.

    Mir waer's nur lieber, ich koennt die Ueberpruefung in den Kopf der while-Schleife stecken

    Das kannst und sollst du auch. Wie es funktioniert, siehst du in meinem Beispielcode.

    randa schrieb:

    Meines Wissens können die streams keine Dateien erzeugen, nur existierende öffnen. Kann sein das ich hier grob falsch liege.

    Jo. Da liegst du grob falsch.

    randa schrieb:

    unsigned char EOF=26; 
    while (!file.eof () && nächstesZeichen!=26)
    

    Schauder. Wo hast du diese Idee her? Nocheinmal: EOF ist ein Makro, dass zu einem negativen Int-Wert expandiert. int nicht unsigned char und negativ nicht 26.

    Blue-Tiger schrieb:

    EOF wird erst nach dem Fileende gesetzt, das ist (leider?) so. Vielleicht hats ja wirklich einen Grund, ich kenn ihn nicht

    Der Grund liegt in der mangelnden Fähigkeit der Streams in die Zukunft blicken zu können. Außerdem sind die Streams nur eine Sicht auf die Datei. Die Datei selbst ist unter der Kontrolle des BS.


Anmelden zum Antworten