Datei Rückwärts lesen



  • ifstream file("abc.txt");
    file.seekg(0,ios::end);
    

    So kann ich den Dateizeiger ja auf das Ende der Datei setzen aber wie kann ich jetzt Rückwärts lesen?

    Ich wollte möglichst nicht den ganzen Dateiinhalt im Speicher sichern und dann den Speicher vom Ende aus durchsuchen...



  • mich wuerde spontan der Use case interessieren.



  • Posix bietet hier mmap an, damit dürfte das ziemlich einfach und performant gehen.

    Ansonsten mit seekg in Chunks arbeiten, erst die letzten 20MB auslesen, dann die vorletzten, etc.



  • Ganz pauschal: Wenn du einfach die komplette Datei Rückwärts in einem String haben willst, dann nimmst du den Streambuf und schiebst in den String nacheinander mit sungetc rein.

    #include <iostream>
    #include <sstream>
    
    int main()
    {
        std::istringstream stream("abcdefg");
        stream.seekg( 0, std::ios_base::end );
    
        std::streambuf* rdbuf = stream.rdbuf();
        std::string str;
    
        typedef std::istringstream::traits_type traits;
        traits::int_type i;
        while( !traits::eq_int_type( i = rdbuf->sungetc(), traits::eof() ) )
            str.push_back( traits::to_char_type(i) );
    
        std::cout << str;
    }
    

    Aber wie ich jetzt verstehe, wird bei diesem Vorgehen ja genau das gemacht - die Datei wird komplett in den Speicher geladen, was du ja nicht willst. Dann bietet sich die Version mit Chunks an.



  • Sone schrieb:

    Ganz pauschal: Wenn du einfach die komplette Datei Rückwärts in einem String haben willst, dann nimmst du den Streambuf und schiebst in den String nacheinander mit sungetc rein.

    Ganz pauschal: NEIN!



  • volkard schrieb:

    NEIN!

    Nein? Willst du es lieber direkt mit dem istream ? Ist doch aber irre lahm, wenn intern noch ein sentry instantiiert wird usw.

    std::istringstream stream("abcdefg");
        stream.seekg( 0, std::ios_base::end );
    
        std::string str;
        while( stream.unget().good() )
            str.push_back( stream.peek() );
    
        std::cout << str;
    

    Edit: std::reverse_copy geht ja leider nicht.



  • Sone schrieb:

    volkard schrieb:

    NEIN!

    Nein?

    Lies doch damit mal eine Datei rückwärts und zeige sie zweichenweise an.



  • @Sone: Wenn schon, dann mit einem eigenen streambuf

    class backbuf : public std::streambuf { 
      std::streambuf* sb; 
    public: 
      explicit backbuf(std::streambuf *sb)
        : sb(sb) { sb->sungetc(); }
    protected: 
      virtual int_type underflow() { return sb->sgetc(); } 
      virtual int_type uflow()     { return sb->sungetc(); } 
    };
    

    Nur leider überschreibt ifstream nicht pbackfail , wie hier nötig.

    Da du offensichtlich zu viel Zeit hast, wäre es eine nette Übung für dich, einen pbackfail_aware_ifstream zu schreiben.



  • Sollte nicht filebuf pbackfail überschreiben, wenn überhaupt?



  • Sone schrieb:

    Sollte nicht filebuf pbackfail überschreiben, wenn überhaupt?

    Ja, das war eine Sprachungenauigkeit.



  • unget (oder die s-Variante) funktioniert doch nur, wenn vorher bereits alles gelesen wurde. D.h. hier würde man im Prinzip alles zwei Mal lesen. Zudem ist nicht garantiert, dass unget beliebig lange funktioniert.

    Attempts to decrease the current location in the stream by one character, making the last character extracted from the stream once again available to be extracted by input operations.

    Wenn die Datei klein ist, würde ich sie einfach komplett in einen string lesen und über reverse_iterator durchlaufen. Ist zwar nicht super und liest auch alles doppelt, aber eben einfach und fehler-unanfällig.

    Man könnte sich auch überlegen, ob man einen Container nutzt, der sehr schnell am Anfang einfügen kann. Dann könnte man jedes get mit einem insert in diesen Container verbinden. Wenn man von Anfang an die Dateigröße kennt, könnte man einen entsprechenden string resizen und eben entsprechend der Position einfügen. Doch auch hier muss man alles auf einmal lesen und... gewinnt vermutlich nichts.



  • Ok, jetzt reicht es mir. Ich faile nicht nochmal mit Streams. Das Meisterbuch ist in einer Woche da, dann werde ich Stream-Experte. 😡


Log in to reply