std::ifstream fehlverhalten - bloedheit oder mingw bug?



  • guten morgen,

    ich habe gerade ein kleines problem mit std::ifstream.
    folgender testcode:

    ifstream fin("test.dat", ios::in | ios::binary);
    	int count = 1;
    	while(!fin.eof())
    	{
    		char c;
    		fin.get(c);
    		cout << "read char number " << count++ << ": '" << c << "'" << endl;
    	}
    	fin.close();
    

    "test.dat" enthaelt genau 5 byte (sagt mir auch windows): "abcde".
    ich habe es auch mit anderen inhalten getestet, und auch ohne ios::binary flag.

    mit "abcde" in test.dat gibt es jedenfalls folgenden output:

    read char number 1: 'a'
    read char number 2: 'b'
    read char number 3: 'c'
    read char number 4: 'd'
    read char number 5: 'e'
    read char number 6: 'e'
    

    egal, was ich probiere, das letzte byte wird immer doppelt gelesen.
    wenn ich nach 5 zeichen die verbleibenden bytes berechne (fin.tellg() von der position nach fin.seekg(0, ios::end) subtrahieren), kommt 0 raus - fin.eof() ist allerdings false.

    mache ich hier irgendwas falsch, oder ist das ein bug, der nicht meinem code entspringt?
    ich habe uebrigens mingw 32-bit und 64-bit probiert (gcc4.4.0 und 4.5.3), alles unter win7 64bit.

    es gab in der vergangenheit scheinbar ab und zu probleme mit ifstream bei mingw, aber was ich ergooglen konnte, war alles andere als aktuell.
    ich glaube auch eher dass es an mir liegt ...

    danke fuer alle hinweise!

    mfg
    julian


  • Mod

    Eigene Blödheit 😃

    Wenn du auf eof prüfst bevor du liest, was passiert dann wohl, wenn du beim Lesen auf eof triffst? Dein Programm macht munter weiter, obwohl nichts gelesen wurde!

    Mach es so:

    while(fin.get(c)) // ...
    


  • SeppJ schrieb:

    Eigene Blödheit 😃

    Wenn du auf eof prüfst bevor du liest, was passiert dann wohl, wenn du beim Lesen auf eof triffst? Dein Programm macht munter weiter, obwohl nichts gelesen wurde!

    Mach es so:

    while(fin.get(c)) // ...
    

    moment ... kann sein dass es einfach zu frueh fuer mich ist, aber
    - eof?
    - lesen
    - eof?
    - lesen
    - eof?
    .....
    so sollte die schleife aussehen.
    nach (und auch vor, wie man es auch lesen mag) jedem lesen wird auf eof() geprueft.
    solange ich keine 2 zeichen zwischen 2 eof-checks lese, sollte das doch klappen?? ich habe das gefuehl, ich blamiere mich gerade, aber ich verstehs echt nicht ...
    (basiert doch alles darauf, dass das byte (char) die kleines einheit ist, die man lesen kann/die vorhanden sein kann?)

    mfg
    julian



  • Du musst zwischen dem Einlesen und der Ausgabe testen, ob das Einlesen überhaupt erfolgreich war. Im Moment läufts so ab:

    fin.get(c); -> c = 'a';
    cout << c;
    fin.get(c); -> c = 'b'
    cout << c;
    fin.get(c); -> c = 'c'
    cout << c;
    fin.get(c); -> c = 'd'
    cout << c;
    fin.get(c); -> c = 'e'
    cout << c;
    fin.get(c); -> fin.eof, daher bleibt c = 'e'
    cout << c;
    


  • hm, ok ...
    d.h. ja dass das eofbit noch nicht gesetzt wird, nachdem das letzte byte gelesen wurde. dann ist das alles klar. finde ich trotzdem komisch ...
    aber danke, ich probiers mal mit dem wissen um diese eigenschaft.

    mfg
    julian



  • Julian__ schrieb:

    d.h. ja dass das eofbit noch nicht gesetzt wird, nachdem das letzte byte gelesen wurde.

    Das Problem ist, dass du im allgemeinen Fall nicht sicher sein kannst, welches das "letzte" Byte ist. Wer weiß, ob beim nächsten Leseversuch - wann immer der sein wird - nicht doch noch ein Zeichen hinzugekommen ist. Das Ende eines Streams kann sich im Laufe der Zeit verändern. Selbst bei Dateien ist das möglich, z.B. wenn gleichzeitig zu deinem Lesezugriff jemand in die Datei schreibt. Darum kann eof immer erst dann gesetzt werden, wenn das Lesen fehlgeschlagen ist.



  • SeppJ schrieb:

    Eigene Blödheit 😃

    Wenn du auf eof prüfst bevor du liest, was passiert dann wohl, wenn du beim Lesen auf eof triffst?

    Eigentlich ist das doch eine dämliche Implementierung vom stream. Wenn ich das letzte richtige Zeichen ('e') einlesen, steht der Lesezeiger auf EOF. Ich brauch doch nicht ein virtuelles EOF einlesen, damit mir der stream EOF sagt. Es gibt garkein EOF in der Datei, sondern nur 5 Zeichen.

    MFK schrieb:

    Das Problem ist, dass du im allgemeinen Fall nicht sicher sein kannst, welches das "letzte" Byte ist. Wer weiß, ob beim nächsten Leseversuch - wann immer der sein wird - nicht doch noch ein Zeichen hinzugekommen ist. Das Ende eines Streams kann sich im Laufe der Zeit verändern. Selbst bei Dateien ist das möglich, z.B. wenn gleichzeitig zu deinem Lesezugriff jemand in die Datei schreibt. Darum kann eof immer erst dann gesetzt werden, wenn das Lesen fehlgeschlagen ist.

    Das Problem ist, dass beim stream eof gesetzt wird und nicht einfach bei ausführen von eof() geprüft wird, ob der Lesezeiger auf EOF zeigt. Nach deiner Logik wäre eof auch falsch, wenn irgendwer nach dem "lesen von EOF" noch was in die Datei schreibt.



  • naja ... kann man sicher lange drueber diskutieren. ihr habt jedenfalls alle recht, danke fuers augenoeffnen.

    mfg
    julian


Anmelden zum Antworten