Teil eines .obj Files (ASCII Text) schnell(!) auslesen... Ideen?



  • Decimad schrieb:

    Werner, das ignore muss doch trotzdem alles einlesen um zu wissen, bis wohin es ignoreren kann/muss!

    ja sicher. Mit 'liest nicht ein' meinte ich: 'liest & speichert nicht in irgendwelchen Variablen'. Wenn nichts zusätzlich gespeichert wird, muss dafür auch kein Memory allokiert werden. Da sehe ich neben dem Zugriff auf das Filesystem den zweiten Flaschenhals.

    Es muss natürlich Zeichen für Zeichen der Datei gelesen werden, denn jedes weitere könnte ein LF oder 'f' sein.

    Decimad schrieb:

    Ich würde lieber nen kleines Tool schreiben, dass mir über Nacht von den Modellen im grässlichen Ascii-Format binäre Versionen erstellt, und mir hinterher nie wieder Gedanken darüber machen 😉

    Dann doch lieber gleich eine Datenbank. Aber ich bin gespannt, was Brusik sagt, wie lange die 5-7MB mit dem ignore_but_f dauern.

    Gruß
    Werner



  • Ich werde das Ganze morgen genau so umsetzen und dann posten was passiert ist bzw. wenns noch eine weitere Idee gibt die Laufzeiten vergleichen ;o)

    Danke derweilen!



  • in der is_endl Funktion muss man vor die Zeile

    std::basic_istream< E, Traits >::sentry ok( in, true );
    

    noch ein

    typename
    

    stellen damit es compiliert... leider bricht der Code aber nach einem Item ab und ich hab keinen Anhaltspunkt wieso.

    Hab das Ganze jetzt mit getline straightforward implementiert, wuerde aber gerne Werners Idee testen sofern jemand eine Antwort auf das Problem hat.

    Cheers



  • Was heißt nach dem ersten Item, genau wo im Code geht der denn raus?



  • Brusik schrieb:

    in der is_endl Funktion muss man vor die Zeile

    std::basic_istream< E, Traits >::sentry ok( in, true );
    

    noch ein

    typename
    

    stellen damit es compiliert...

    Das stimmt; und in Zeile 18 muss vor das 'std::basic_istream< E, Traits >::int_type' auch ein typename. Ich habe das im Posting von is_endl korrigiert. Der MS-VC ist da völlig großzügig ..

    Brusik schrieb:

    leider bricht der Code aber nach einem Item ab und ich hab keinen Anhaltspunkt wieso.

    Probier mal (nur für Debug-Zwecke) folgendes:

    while( datei >> ignore_but_f )
        {
            for( int idx, value; ; )
            {
                if( is_endl( datei ) ) break;
                if( !(datei >> idx) ) { cerr << "Err: idx" << endl; break; }
                if( !(datei >> Char<'/'>) ) { cerr << "Err: Char<'/'>" << endl; break; }
                if( !(datei >> value) ) { cerr << "Err: value" << endl; break; }
    
                array[ idx ] = value;
            }
        }
        if( !datei.eof() )
        {
            cerr << "Fehler beim Lesen" << endl; // <== hier Break Point setzen und in 'datei' reingucken, falls möglich
        }
    

    Gruß nach Wellington
    Werner

    @Edit: if( !datei.eof() ) hinzugefügt



  • Danke für den Debug-Code Werner, der funktioniert genau wie erwartet völlig ohne Probleme und gibt alle Daten wie gewünscht aus!

    Der ursprüngliche Code...

    for( int idx, value; !is_endl( inFile ) && inFile >> idx >> Char<'/'> >> value; )
    

    ... lässt sich zwar kompilieren, aber Eclipse vermerkt dazu:

    Multiple Markers at this Line
    -Syntax Error
    -Syntax Error
    

    und gibt nur die idx bzw. values der erste "f" Zeile zurück (@Eisflamme: er biegt nach der ersten Zeil ab). Sehr eigenartig...



  • Der kompiliert aber zeigt an "Syntaxfehler"?

    So geht's auch nich?

    int idx, value;
    for( ; !is_endl( inFile ) && inFile >> idx >> Char<'/'> >> value; )
    


  • Nein, an das hatte ich schon gedacht... das macht leider keinen Unterschied. Das Schräge ist ja wirklich der Umstand, dass der Code Compiliert aber nicht so arbeitet wie erwartet.

    Ich habe testweise den Code aneinander gereiht:

    int idx, value;
    		for( ; !is_endl( inFile ) && inFile >> idx >> Char<'/'> >> value; ) {
    			cout << value << " " << idx << endl;
    		}
    
    		for(/* int idx, value */; ; ) {
    

    und erhalte folgende Ausgabe:

    File opened
    ... Daten erste Zeile
    Err: idx
    Fehler beim Lesen



  • Brusik schrieb:

    Danke für den Debug-Code Werner, der funktioniert genau wie erwartet völlig ohne Probleme und gibt alle Daten wie gewünscht aus!

    Heißt das, dass obiger Code die obj-Datei ohne Fehler einliest ... und die ursprüngliche Fassung zwar übersetzt, aber es nicht tut. Das würde ja bedeuten, dass der gcc falsch übersetzt 😕

    Brusik schrieb:

    Ich habe testweise den Code aneinander gereiht:

    int idx, value;
    		for( ; !is_endl( inFile ) && inFile >> idx >> Char<'/'> >> value; ) {
    			cout << value << " " << idx << endl;
    		}
    
    		for(/* int idx, value */; ; ) {
    

    und erhalte folgende Ausgabe:

    File opened
    ... Daten erste Zeile
    Err: idx
    Fehler beim Lesen

    Dies wiederum ist völlig logisch, da die for-Schleife nur genau eine Zeile ohne das führende 'f' liest. Stellst Du sie zweimal hintereinander, so trifft das zweite datei>>idx auf ein 'f' oder einen anderen Buchstaben, und liefert demzufolge einen Fehler.

    Generiere Dir doch einfach eine kleine obj-Datei mit einer Handvoll Zeilen zum Üben. Und versuche den Code zu debuggen. Hast Du im Debugger Zugriff auf den streambuf von 'datei'? Und kannst Du sehen wo die aktuelle Schreibposition ist?

    Falls dies in Deiner Umgebung nicht geht, so kannst Du folgenden streambuf

    class LC : public std::streambuf
    {
    public:
        typedef std::streambuf::int_type int_type;
        typedef std::streambuf::traits_type traits_type;
        explicit LC( std::streambuf* source ) 
            : m_line(0), m_column(0)
            , m_lf_occurs( true )
            , m_source( source )
            , m_c()
        {}
    
        friend std::ostream& operator<<( std::ostream& out, const LC& lc )
        {
            return out << "Line " << lc.m_line << " Column " << lc.m_column;
        }
    protected:
        virtual int_type underflow()
        {
            const int_type m = m_source->sbumpc();
            if( !traits_type::eq_int_type( m, traits_type::eof() ) )
            {
                if( m_lf_occurs )
                {
                    ++m_line;
                    m_column = 0;
                    m_lf_occurs = false;
                }
                m_c = traits_type::to_char_type( m );
                setg( &m_c, &m_c, &m_c + 1 );
                if( m_c == '\n' ) // LF
                    m_lf_occurs = true;
                ++m_column;
            }
            return m;
        }
    
    private:
        int m_line, m_column;
        bool m_lf_occurs;
        std::streambuf* m_source;
        char m_c;
    };
    

    .. benutzen, Der gibt Dir den aktuellen Stand Deines Lesezeigers aus, wenn Du ihn zwischen den file_buf und einen istream einhängst - geht etwa so:

    ifstream datei_( "input.obj" );
        LC lc( datei_.rdbuf() );
        istream datei( &lc );
    
        while( datei >> ignore_but_f )
        {
            for( int idx, value; !is_endl( datei ) && datei >> idx >> Char<'/'> >> value; )
                array[ idx ] = value;
        }
        if( !datei.eof() )
        {
            cerr << "Fehler beim Lesen an Position: " << lc << endl;
        }
    

    wie lange dauert denn so eine 5-7MB-Datei?

    Gruß
    Werner



  • Werner Salomon schrieb:

    Heißt das, dass obiger Code die obj-Datei ohne Fehler einliest ... und die ursprüngliche Fassung zwar übersetzt, aber es nicht tut.

    Völlig richtig, genau so sieht es aus... und zwar sowohl auf einer Linux als auch auf einer Mac Maschine (gcc 4.3.3 bzw. 4.2.1)!!!

    Aber es wird noch spannender 😉

    LC lc( inFile_.rdbuf() );
    	    istream inFile( &lc );
    
    	    while( inFile >> ignore_but_f )
    	    {
    	        for( int idx, value; !is_endl( inFile ) && inFile >> idx >> Char<'/'> >> value; ) {
    	        	cout << value << "-" << idx << endl;
    	        }
    
    	    }
    	    if( !inFile.eof() )
    	    {
    	        cerr << "Fehler beim Lesen an Position: " << lc << endl;
    	    }
    

    ... funktioniert ebenfalls ohne Murren und gibt alle idx bzw. values korrekt aus

    Werner Salomon schrieb:

    wie lange dauert denn so eine 5-7MB-Datei?

    Ich komm erst Mo. wieder an die Files, und es sind 100 - 140MB Files(!) nicht 5MB, sonst würde ich doch gar nicht einen Aufstand wegen Geschwindigkeit etc. machen 😉



  • Brusik schrieb:

    Werner Salomon schrieb:

    Heißt das, dass obiger Code die obj-Datei ohne Fehler einliest ... und die ursprüngliche Fassung zwar übersetzt, aber es nicht tut.

    Völlig richtig, genau so sieht es aus... und zwar sowohl auf einer Linux als auch auf einer Mac Maschine (gcc 4.3.3 bzw. 4.2.1)!!!

    dann scheint es wohl ein Problem des Compilers zu sein .. unabhängig von der Plattform.

    Falls das mit std::istream geht, aber nicht mit std::ifstream, dann kannst Du in Deinem Fall die Variable inFile einfach casten .. ich mein' das so:

    ifstream inFile_( "input.obj" );
        istream& inFile = inFile_;
    

    Das sollte dann eigentlich funktionieren. Und man verliert auch keine Performance.

    Benutzt Du überhaupt std::ifstream oder öffnest Du einen std::fstream?

    Gruß
    Werner


Anmelden zum Antworten