Via istream_iterator N aufeinanderfolgende Zeichen aus einer Datei lesen



  • Abend,

    ich versuche gerade, eine bestimmte Anzahl von Zeichen ab einer bestimmten Position via istream_iterator zu lesen, habe aber so meine Schwierigkeiten damit. Zum Beispiel will ich aus der Datei foo.bin 10 Zeichen lesen, von Postition 100 bis 109. Probleme bereitet mir nun, einen Iterator auf das Ende zu setzen:

    #include <fstream>
    #include <iterator>
    #include <string>
    
    int main()
    {
    	std::ifstream begin("foo.bin",std::ios_base::binary);
    	begin.seekg(100,std::ios_base::beg);
    
    	std::string content(std::istream_iterator<char>(begin),std::istream_iterator<char>(/*end*/));
    }
    

    Ich habe versucht, einen Iterator auf dieselbe Position wie begin zu setzen und ihn dann 10x zu inkrementieren. Irgendwie schwachsinnig und es hat auch nicht funktioniert; ich habe einen leeren String bekommen. Gibt es überhaupt eine Möglichkeit, das Ganze mit istream_iterator zu machen?

    Danke im Voraus.



  • Du kannst mit std::copy_n eine bestimmte Anzahl kopieren und mittels std::back_inserter zum String hinzufügen:

    std::copy_n(std::istream_iterator<char>(begin), 10, std::back_inserter(content));
    


  • Stimmt :), aber wie schauts ohne C++11 aus. 😛


  • Mod

    Gugelmoser schrieb:

    Stimmt :), aber wie schauts ohne C++11 aus. 😛

    Dann programmier dir copy_n. Die andere Methode, sich einen zählenden istream_iterator zu schreiben ist viel, viel aufwändiger.



  • Auf http://en.cppreference.com/w/cpp/algorithm/copy_n kannst du auch ein mögliches copy_n anschauen/ übernehmen 😋 :

    template< class InputIterator, class Size, class OutputIterator>
    OutputIterator copy_n(InputIterator first, Size count, OutputIterator result)
    {
        if (count > 0) {
            *result++ = *first;
            for (Size i = 1; i < count; ++i) {
                *result++ = *++first;
            }
        }
        return result;
    }
    


  • macian schrieb:

    if (count > 0) {
            *result++ = *first;
            for (Size i = 1; i < count; ++i) {
                *result++ = *++first;
            }
        }
    

    Diese Implementierung finde ich seltsam, wieso nicht ganz einfach so...

    if( count>0 )
    	{
    		for(Size i=0; i<count; ++i,++first,++result)
    		{
    			*result = *first;
    		}
    	}
    


  • SeppJ schrieb:

    Gugelmoser schrieb:

    Stimmt :), aber wie schauts ohne C++11 aus. 😛

    Dann programmier dir copy_n. Die andere Methode, sich einen zählenden istream_iterator zu schreiben ist viel, viel aufwändiger.

    Aber Achtung - ein copy_n ist wider Erwarten gar nicht trivial. Eine 'normale' Implementierung führt in Kombination mit std::istream_iterator sofort zu einem Fehler. Mit Rücksicht auf den input-iterator darf die Quelle (istream_iterator) nur N-1-mal inkrementiert werden.
    copy_n mit N==0 ist übrigens nicht zulässig!

    Falsch wäre

    template< typename Src, typename Sz, typename Dst >
        Dst copy_n( Src src, Sz count, Dst dst )
        {
            for( ; count > 0; --count, ++dst, ++src ) // 'src' wird 'count'-mal inkrementiert
                *dst = *src;
            return dst;
        }
    

    Korrekter ist:

    template< typename Src, typename Sz, typename Dst >
        Dst copy_n( Src src, Sz count, Dst dst )
        {
            assert( count > 0 );
            *dst = *src;
            while( --count > 0 )
                *++dst = *++src; // 'src' wird 'count-1'-mal inkrementiert
            return ++dst;
        }
    

    Gruß
    Werner



  • Werner Salomon schrieb:

    Aber Achtung - ein copy_n ist wider Erwarten gar nicht trivial. Eine 'normale' Implementierung führt in Kombination mit std::istream_iterator sofort zu einem Fehler. Mit Rücksicht auf den input-iterator darf die Quelle (istream_iterator) nur N-1-mal inkrementiert werden.
    copy_n mit N==0 ist übrigens nicht zulässig!

    Ah, ok, das erklärt, warum es auf diese Art und Weise implementiert ist. Danke euch 🙂


Anmelden zum Antworten