Wiederholtes lesen einer Datei



  • Ich versuche im Moment ein Programm zu entwickeln, welches eine Textdatei liest in der sich ein Labyrinth befindet.
    Wände werden hierbei durch das Raute-Zeichen dargestellt und freie Gänge durch Whitespaces.
    Ich öffne also die Datei und suche nach dem Eingang und der Labyrinthbreite.

    while(!labyrinth_f.eof())
    	{
    
    		labyrinth_f >> digit;
    
    		switch(digit)
    		{
    			case '#':			
    				digitcount++;
    				break;
    
    			case ' ':
    				digitcount++;
    				if(linecount == 0)
    				{
    					startpoint = digitcount;
    
    					//cout << "Eingang gefunden an der Stelle: "<<startpoint<<"\n";
    				}
    				break;
    
    			case '\r':
    				break;
    
    			case '\n':
    				if(linecount == 0)
    				{
    					linelength = digitcount;	
    				}				
    				linecount++;
    				break;
    
    			default:
    				break;
    		}
    	}
    

    Da in weiterer Folge mehrere Labyrinthe eingelesen werden sollen, erstelle ich ein 2-dimensionales dynamisches Array in welches ich das Labyrinth speichern möchte.

    Labyrinth::Labyrinth(int linelength)
    {
    
    	lab_row=linelength;
    	lab_col=linelength;
    	a=new char* [lab_row];
    	for(int i=0;i<lab_row;i++)
    	*(a+i)=new char[lab_col];
    }
    

    Ich setze den get-Pointer des Streams also wieder an den Anfang der Datei:

    labyrinth_f.seekg (0, ios::beg);
    

    Versuche ich nun jedoch ein char. auszulesen und ausgeben zu lassen oder in das dyn. Array zu speicher, so erhalte ich keine Ausgabe.

    labyrinth_f.seekg(0, ios::beg);
    	while(!labyrinth_f.eof())//Test
    	{
    		labyrinth_f >> digit;
    		cout << digit;
    	}
    

    Ich verstehe mittlerweile echt nicht mehr woran das liegen könnte.
    Ich habe außerdem auch versucht den ersten Stream zu closen und einen neuen anzulegen, welche auf die selbe Datei zugreift, dies funktioniert übrigens auch nicht.


  • Mod

    while(!labyrinth_f.eof())
        {
    
            labyrinth_f >> digit;
    
            // Verarbeitung von digit
    

    Das ist schon einmal ganz schlecht. Was, wenn deine Leseaktion fehlschlägt, weil das Dateiende erreicht wird? Dann wird ein ungültiges digit weiterverarbeitet und erst beim nächsten Schleifendurchgang abgebrochen. Ganz zu schweigen von der Möglichkeit, dass auch andere Sachen fehlschlagen können und du dann in einer Endlosschleife landen würdest. Die Reihenfolge sollte Lesen, prüfen, verarbeiten sein. Oder kurz:

    while (labyrinth_f >> digit)
     {
       // Verarbeitung von digit
     }
    

    So wird digit eingelesen, dann wird geprüft ob der Stream noch gültig ist (dann hat nämlich auch das Einlesen funktioniert) und erst dann wird verarbeitet.

    Ich setze den get-Pointer des Streams also wieder an den Anfang der Datei:

    Wenn du vorher gelesen hast bis eof war, dann befindet sich der Stream noch in einem Fehlerzustand, den du erst durch .clear() beheben musst, bevor du ihn weiter benutzen kannst.

    Gegenfrage: Warum liest du die Labyrinthe nicht erst ein und suchst dann die Eingänge in den gelesenen Daten?

    Ich habe außerdem auch versucht den ersten Stream zu closen und einen neuen anzulegen, welche auf die selbe Datei zugreift, dies funktioniert übrigens auch nicht.

    Sollte es aber. Und das close brauchst du auch nicht, die Streams gehen automatisch zu, wenn sie den Gültigkeitsbereich verlassen.

    Allgemeinfloskel: Wieso programmieren bloß alle Anfänger mit den Streamklassen so, als ob sie C-Dateipointer wären? Gibt es da draußen nur schlechte Anleitungen?



  • Ich denke, das liegt daran, daß der Seek das EOF-Flag nicht wieder zurücksetzt.
    Daher rufe noch

    labyrinth_f.clear();
    

    vorher auf.

    Aber besser wäre wohl, du öffnest so lokal wie möglich die Datei, d.h. mittels RAII:

    {
      ifstream iff("Labyrinth.txt"); // bzw. variabler Dateiname
    
      // lesen
    } // Datei wird automatisch wieder geschlossen
    

    und beim nächsten Aufruf dieser Methode hast du dann auch keine Probleme mehr wegen den internen Status-Flags.



  • @SeppJ:
    Erstmal vielen Dank für die ausführliche Erklärung.
    Meine Frage wäre, was könnte dazu führen das der Stream nicht mehr gültig ist, bzw. die Leseaktion fehlschlägt, ausser das Erreichen von EOF?
    Das EOF in einem Fehlerzustand endet wusste ich nicht, vielen Dank.
    Die C-ähnliche Programmierart liegt wohl daran das ich ein halbes Jahr nur C gelernt und programmiert habe und erst seit wenigen Tagen auf C++ umgestiegen bin.

    @Th69:
    Ja, es lag an dem von euch beiden erwähnten EOF-Flag.
    Danke für den RAII-Tipp.


  • Mod

    mynik schrieb:

    @SeppJ:
    Meine Frage wäre, was könnte dazu führen das der Stream nicht mehr gültig ist, bzw. die Leseaktion fehlschlägt, ausser das Erreichen von EOF?

    So ziemlich alles. Die wichtigste Art des Fehlschlags ist, dass das Format nicht passte, du z.B. eine Zahl einlesen möchtest, an der Stelle aber Buchstaben stehen. Und Sachen, wie dass die Datei gar nicht existiert oder nicht gelesen werden darf.



  • Die letzten beiden Fehler fange ich mit der Abfrage

    ifstream labyrinth_f (argv[1]);
    labyrinth_f.unsetf(ios_base::skipws);
    
    if(!labyrinth_f)
    {
         cerr << "Unable to open maze.\n";
         exit(1);
    }
    

    welche ich vor der Verarbeitung platziert habe, soweit ich weiß ab.

    Bei dem Rest hast du nat. recht, danke.


Log in to reply