Textfile ab Zeile x einlesen?



  • Man moege mir verzeihen, denn sicherlich wurde diese Frage hier schon mal gestellt und bestimmt auch beantwortet. Nur ist es leider so, dass ich gerade erst mit C++ anfange und daher noch nicht so reicht weiss, wonach ich eigentlich suchen soll.

    Nach meinen ersten Gehversuchen stehe ich naemlich vor dem Problem ein Textfile, die Zeilen habe variable Laengen, als Stream einzulesen. Das waere bis her ja auch kein Problem, nur moechte ich die ersten x Zeilen einfach ueberspringen und nur die Zeilen x+1 bis zum Ende der Datei einlesen.

    Im Moment benutze ich dafuer einen Zaehler, also so in der Art von if(n < x) {n++;}, was zwar funktioniert, aber nun wirklich nicht sonderlich elegant ist.

    Kann mir jemand da mal auf die Spruenge helfen?

    Hoffentlich habe ich mich verstaendlich genug ausgedrueckt ...

    Guenther
    Davao City, Philippines, Planet Earth



  • Etwas besseres wirst du wohl kaum finden - Dateiverarbeitung arbeitet zeichenweise und nicht zeilenweise, darum gibt es zwar eine "gehe zum x-ten Zeichen" Methode in fstream (seekg() bzw. seekp()), aber keine "gehe zur x-ten Zeile" - die einzige Möglichkeit für dich besteht darin, x-1 Zeilen zu lesen und zu verwerfen, danach stehst du am Anfang der x-ten Zeile.

    Optimierungsmöglichkeiten:

    • Lies die Datei einmal komplett ein und merk dir die Position der Zeilenanfänge in einem vector<size_t>
    • Speichere die Datei komplett in einem vector<string> und arbeite mit der RAM-Version anstatt ständig auf Platte zuzugreifen
    • ...


  • CStoll schrieb:

    Dateiverarbeitung arbeitet zeichenweise und nicht zeilenweise, darum gibt es zwar eine "gehe zum x-ten Zeichen" Methode in fstream (seekg() bzw. seekp()), aber keine "gehe zur x-ten Zeile" ....

    Danke, denn jetzt wo ich Deine Zeilen lese, faellt's mir natuerlich auch wie Schuppen von den Augen ....

    Magst Du dennoch mal einen Blick auf meinen Code werfen und mir sagen, ob ich das so lassen kann oder aber irgendwo generell was falsch mache?

    // reading a text file
    #include <iostream>
    #include <fstream>
    #include <string>
    
    using namespace std;
    
    int main () {
      string line;
      size_t pos;
      int n = 0;
    
      ifstream myfile ("daten.csv"); 
    
    		if (myfile.is_open()) {
    			while (!myfile.eof()) {
    				getline (myfile,line);
    
    				if (n > 7) {
    					pos = line.find(";");
    					line = line.substr (pos+1);
    	  	    cout << line << endl;      
          	}
    	      n++;
      	  }
        	myfile.close();
    	  }
    
    	  else cout << "Unable to open file\n\n"; 
    
    	return 0;
    }
    

    Wohlbemerkt, der Code funktioniert so einwandfrei, ich will mir nur nicht gleich am Anfang irgendwelche 'Unsitten' angewoehnen was die Codierung angeht ...



  • alternativ zum vector kannst du auch die deque verwenden. Das duerfte gerade bei grossem x und grossen Dateien von Vorteil, dan du dann die ersten x-1 Zeilen schnell wieder rauswerfen kannst und meinen Informationen zufolge der vector in vielen Implementationen ein klein wenig speicheraufwaendiger ist.

    /edit: was den code angeht faellt als erstes auf, dass deine Einrueckungen eher willkuerlich zu sein scheinen, das macht den code nur sehr schwer lesbar. (z.B. muss man dreimal hinschauen um zu merken dass das file.close() noch im if-block steht). Ausserdem wuerde ich das mit dem Zaehler etwas anders gestalten, a la

    while (!file.eof() && n<7) {getline(file, line); n++;} //hier einfach hochzaehlen
    while (!file.eof()){/*...*/}
    

    oder so aehnlich, das spart dir die if-Abfrage bei jeder der restlichen 500(000?) Zeilen.



  • pumuckl schrieb:

    ... was den code angeht faellt als erstes auf, dass deine Einrueckungen eher willkuerlich zu sein scheinen, das macht den code nur sehr schwer lesbar. (z.B. muss man dreimal hinschauen um zu merken dass das file.close() noch im if-block steht).

    Jetzt wo Du's sagst, sehe ich es natuerlich auch. Da werde ich in Zukunft auf jeden Fall drauf achten.

    Ausserdem wuerde ich das mit dem Zaehler etwas anders gestalten, a la

    while (!file.eof() && n<7) {getline(file, line); n++;} //hier einfach hochzaehlen
    while (!file.eof()){/*...*/}
    

    oder so aehnlich, das spart dir die if-Abfrage bei jeder der restlichen 500(000?) Zeilen.

    So wie Du's mir gerade erklaert hast leuchtet das ein, danke, habe ich sofort uebernommen.



  • gboelter schrieb:

    .. nur moechte ich die ersten x Zeilen einfach ueberspringen und nur die Zeilen x+1 bis zum Ende der Datei einlesen.
    Im Moment benutze ich dafuer einen Zaehler, also so in der Art von if(n < x) {n++;}, was zwar funktioniert, aber nun wirklich nicht sonderlich elegant ist.

    man kann es aber recht schön verpacken. Etwa in der Form:

    #include <iostream>
    #include <fstream>
    #include <string>
    #include <limits> // std::numeric_limits
    
    // -- überspringt beim Einlesen 'n' Zeilen
    struct skiplines
    {
        explicit skiplines( int nlines ) : m_nlines( nlines ) {}
        friend std::istream& operator>>( std::istream& in, const skiplines& x )
        {
            for( int n = x.m_nlines
                    ; n > 0 && in.ignore( std::numeric_limits< std::streamsize >::max(), '\n' )
                    ; --n )
                ;
            return in;
        }
    private:
        int m_nlines;
    };
    
    // -- und hier kommt die eigentliche Anwendung
    int main()
    {
        using namespace std;
        ifstream myfile( "daten.csv" );
        if( !myfile.is_open() )
        {
            cerr << "Fehler beim Oeffnen der Datei" << endl;
            return -1;
        }
        myfile >> skiplines( 8 ); // 8 Zeilen überlesen
    
        // ab hier dann das einlesen, was gewünscht ist
        for( string line; getline( myfile.ignore( numeric_limits< streamsize >::max(), ';' ), line ); )
        {
            cout << line << endl;
        }
        return 0;
    }
    

    Gruß
    Werner

    Edit: Original-Code überliest die ersten 8 Zeilen!



  • pumuckl schrieb:

    alternativ zum vector kannst du auch die deque verwenden. Das duerfte gerade bei grossem x und grossen Dateien von Vorteil, dan du dann die ersten x-1 Zeilen schnell wieder rauswerfen kannst und meinen Informationen zufolge der vector in vielen Implementationen ein klein wenig speicheraufwaendiger ist.

    Das halte ich für'n Gerücht, zumal die Deque oft als Ringpuffer über einem Vektor implementiert ist.

    /EDIT: Schlecht zitiert. Der erste Teil Deiner Aussage stimmt natürlich auf jeden Fall.



  • Dann steht das in meiner C++-Referenz falsch:

    Deque [...] Im Vergleich zu vector ist der Zugriff auf beliebige Positionen etwas langsamer, dafuer ist die Speicherverwaltung meist guenstiger.



  • Werner Salomon schrieb:

    .... man kann es aber recht schön verpacken. Etwa in der

    Danke Werner,

    das geht zwar im Moment noch 'ein wenig' ueber meinen Horizont, aber den Code werde ich auf jeden Fall studieren ....

    Guenther



  • Und noch ein Ergänzungstipp: Statt nur eof() abzufragen, solltest du lieber alle Fehlerflags überprüfen ( while(file.good() && ...) oder kürzer while(file && ...) ) - sonst landest du in einer Endlosschleife, wenn ein "normaler" Lesefehler auftritt.



  • CStoll schrieb:

    Und noch ein Ergänzungstipp: Statt nur eof() abzufragen, solltest du lieber alle Fehlerflags überprüfen ....

    Das war jetzt Gedankenuebertragung, denn gerade das habe ich heute beim Studium dieses genialen Forums gerlernt, oder besser "begriffen".

    So wie ich jetzt auch endlich weiss, wie sich das mit den namespaces verhaelt.

    Wirklich ein tolles Forum ....


Anmelden zum Antworten