DAtei öffnen --- auslesen



  • #include <stdio.h> 		//für printf 
    #include <conio.h> 		//für getch(); 
    #include <process.h>    //für fprintf
    
    // crt_fopen.c
    /* This program opens two files. It uses
     * fclose to close the first file and
     * _fcloseall to close all remaining files.
     */
    
    #include <stdio.h>
    
    FILE *stream, *stream2;
    
    main()
    {
        char cDateiAuswahl;
        int numclosed;
        char line[100];
    
        printf("********** Datei-Auswahl **********\n\n");
        printf("1. Airplus\n");
        printf("2. Vodafone\n");
        printf("3. Beenden\n\n");
    
        printf("Bitte waehlen Sie nun, welche Datei sie verarbeiten wollen.\n\n");
        printf("Ihre Eingabe: ");
        scanf("%i",&cDateiAuswahl);
        printf("\n\n\n");
    
        switch(cDateiAuswahl)
    {
       case 1:  printf("********** Airplus **********\n");
    
       /* Open for read (will fail if file "Air_Plus_Beispiel.xls" does not exist) */
      if( (stream  = fopen( "Air_Plus_Beispiel.csv", "r" )) != NULL )
      {
           printf( "\nThe file 'Air_Plus_Beispiel.csv' was opened\n" ); 
    
           //open for write
           if( (stream2 = fopen( "test.csv", "w+" )) == NULL )
                  printf( "\nThe file 'test.csv' was not opened\n" );
           else
                 printf( "\nThe file 'test.csv' was opened\n" );
    
    //schleife bis zum ende
    
           //read line 
           while(fgetc(stream) != EOF) //bis zum fileende durchlaufen
           { 
               line[200] = fgetc(stream);
    
                  while (fgetc(stream) != '\n');//bis zum zeilenende durchlaufen
                  {    
                      if( fgets( line, 200, stream ) == NULL) 
                         printf( "fgets error\n" ); 
                      else 
                         printf( "\n%s\n", line); 
                  }    
          }      
           fclose( stream );
    
    }  
      else
         printf( "\nThe file 'cAir_Plus_Beispiel.csv' was not opened\n" );
    
    /* Close stream */
           if( fclose( stream ) )
                 printf( "\nThe file 'Air_Plus_Beispiel.csv' was not closed\n" );
    
       /* All other files are closed: */
             numclosed = _fcloseall( );
                printf( "\nNumber of files closed by _fcloseall: %u\n", numclosed );
    
                  break;
       case 2:  printf("********** Vodafone **********\n");
                  break;
       case 3:  printf("********** Programm wird beendet **********\n");
                  break;
       default :  printf("********** Falsche Eingabe! **********\n");
                  break;
    }
        system("pause");
    
    }
    

    so, nun hab ich das mit der schleife *fg*
    und nuuuuuuuuuuuuu?



  • Und nun kannst du die Schleife(n), die du gemacht hast über den Haufen schmeißen und nochmal drüber nachdenken.

    Ok so gemein bin ich auch wieder nicht. Du hast das ganze viel zu umständlich gemacht und leider auch falsch.

    Erstmal zu fgets(). fgets() liest aus einer Datei Zeichen ein und zwar bis zum nächsten Zeilenumbruch (\n), bis zum Dateiende (letzte Zeile) oder bis die maximale Einleselänge erreicht wird (bei dir ist das 100 = Größe deiner Variablen line). Zurückgegeben wird von fgets() die Anzahl der eingelesenen Zeichen und im Fehlerfall 0 (dazu zählt auch der Fall, wenn der Dateizeiger am Ende der Datei steht und man versucht etwas zu lesen).

    So und nun, was du genau tun sollst:
    Lese eine Zeile ein und gib diese aus solange das Dateiende nicht erreicht wurde.

    Das solltest du als Quellcode nun schreiben. Kleiner Tipp: Es dürften nur 2 Codezeilen sein (Zeilen nur mit Klammern nicht mitgezählt ;))



  • mmmh...mal ganz dreist gefragt, kannst du da an den quelltext nicht mal bissl rumfuschen? *wegrennt*

    also die eine schleife ist überflüssig wenn ich fgets nehme anstatt fgetc



  • Die ganze Schleife stimmt schlicht und ergreifend nicht. Mal davon abgesehen, dass sie einen typischen Bufferoverflow enthält, der sich ganz böse äußern kann.

    Lass dir nochmal den Satz durch den Kopf gehen und versuch ihn in C-Code umzusetzen:
    Solange das Dateiende nicht erreicht ist, lese eine Zeile ein und gib diese am Bildschirm aus.

    Die Schlüsselwörter hab ich dir markiert.

    Nochmal zu dem was du wissen solltest.
    fgets() liest eine Zeile aus der Datei ein und gibt 0 zurück, wenn ein Fehler aufgetreten ist oder das Dateiende erreicht (gelesen) wurde.



  • #include <stdio.h>
    
    #include <string.h>
    
    #define INPUTFILE "Air_Plus_Beispiel.csv"
    #define OUTPUTFILE "test.csv"
    #define DELIM ";"
    
    int main (void) {
    	FILE * input_stream, *output_stream;
    	char line[BUFSIZ];
    	char *tokens[BUFSIZ];
    	int i;
    	char * temptok;
    
    	input_stream  = fopen( INPUTFILE, "r"); // Eingabe oeffnen
    	if (input_stream == NULL) {
    		printf( "\nThe file '%s' was not opened\n", INPUTFILE );
    		exit(2);
    	};
    
    	output_stream =  fopen( OUTPUTFILE, "w"); //Ausgabe oeffnen
    	if (output_stream == NULL) {
    		printf( "\nThe file '%s' was not opened\n", OUTPUTFILE );
    		exit(2);
    	};
    
    	while (!feof(input_stream)) { //Solange kein End-Of-File in der Eingabe...
    		fgets (line, BUFSIZ, input_stream);
    
    		i = 0;
    		temptok = line;
    		while ( (tokens[i] = strtok(temptok, DELIM)) != NULL) //strtok erwartet folgende Parameter:
    //temptok ist die zu splittende Zeile beim 1. Aufruf und NULL bei nachfolgenden Aufrufen;
    //der zweite Parameter sind die Grenzen der Tokens
    // Konstante DELIM oben auf ";" definiert
    //strtok gibt einen Zeiger auf den nächsten Token zurück oder NULL, wenn kein Token mehr da ist 
    //(String zu Ende tokenisiert)
    
    //weise tokens[i] die Adresse des nächstens Tokens zu; wenn die Adresse nicht NULL ist, mache Folgendes: ...
            {
    			temptok = NULL;
    			i++;
    		};
    		fprintf (output_stream, "%s;\n",tokens[3]);
    		fprintf (output_stream, "%s;\n",tokens[4]);
    		fprintf (output_stream, "%s;\n",tokens[5]);
    		fprintf (output_stream, "%s;\n",tokens[13]);
    		fprintf (output_stream, "%s;\n",tokens[17]);
    		fprintf (output_stream, "%s;\n",tokens[18]);
    		fprintf (output_stream, "%s;\n",tokens[19]);
    		fprintf (output_stream, "%s;\n",tokens[25]);
    		fprintf (output_stream, "%s;\n",tokens[27]);
    		fprintf (output_stream, "%s;\n",tokens[31]);
    		fprintf (output_stream, "%s;\n",tokens[38]);
    	};
    
    	fclose (output_stream);
    	fclose (input_stream);
    
    	return (0);
    };
    

    yeah 😃 so, nun muss es das noch nebeneinander schreiben, also da wo ich die eine zeile eingelesen habe, soll auch in einer zeile ausgegeben werden. wo ist der haken?



  • \n erzeugt einen Zeilenumbruch ;).

    Richtige Lösung des Ganzen. Bist du selber dahintergekommen oder hattest du Hilfestellung (außer von mir ;))?



  • Ich hätt auch im Zweifel die vielen fprintfs durch etwas in der Art ersetzt:

    /* auszugebende felder */
    int af[] = { 3, 4, 5, 13, 17, 18, 19, 25, 27, 31, 38, -1 };
    int i;
    
    /* ... */
    
    for(i = 0; af[i] >= 0; ++i)
      fprintf(output_stream, "%s;\n", tokens[af[i]]);
    

    Das ist nachher einfacher erweiterbar, wenn du z.B. mal andere Felder ausgeben willst.



  • Whoops, das \n aus dem Formatstring muss natürlich raus, wenns in eine Zeile soll:

    for(i = 0; af[i] >= 0; ++i)
      fprintf(output_stream, "%s;", tokens[af[i]]);
    fputc('\n', output_stream); /* Nach Ende der Zeile einen Zeilenumbruch raus schreiben*/
    


  • @AJ, hatte hilfe, allein wär ich nie so weit gekommen...



  • noch eine frage. ich muss ja trotzdem noch dies in das hauptmenü einbauen.

    einfach so wie ich ganz am anfang angefangen hatte? also mit case arbeiten?



  • Troja2k schrieb:

    noch eine frage. ich muss ja trotzdem noch dies in das hauptmenü einbauen.

    einfach so wie ich ganz am anfang angefangen hatte? also mit case arbeiten?

    Ja.

    Dachte mir schon, dass du dabei Hilfe hattest. Ich hoffe du hast auch was draus gelernt. Hast du auch verstanden was da gemacht wird?



  • ja, bin eben nochmal teil für teil durchgegangen und hab hinter fast jede zeile einen kommentar geschrieben *g*

    bin auf jedenfall dankbar, das es foren wie diese gibt 👍 👍 👍



  • hallo ihr, besonders AJ *g*

    ich brauch nochmal hilfe. um alles zu verstehen. wieso da nun ein pointer ist etc.

    nochmal mein code bis jetzt:

    #include <stdio.h>
    
    #include <string.h>
    
    #define INPUTFILE "Air_Plus_Beispiel.csv" //inputfile wird definiert
    #define OUTPUTFILE "test.csv" //outputfile wird definiert
    #define DELIM ";" //ab ; neu
    
    int main (void) {
    	FILE * input_stream, *output_stream;  //<-- ?
    	char line[BUFSIZ];  //<-- ?
    	char *tokens[BUFSIZ]; //<-- ?
    	int i;
    	char * temptok;  //<-- ?
    	char file;
    
    	printf("********** Datei-Auswahl **********\n\n");
        printf("1. Airplus\n");
        printf("2. Vodafone\n");
        printf("3. Beenden\n\n");
    
        printf("Bitte waehlen Sie nun, welche Datei sie verarbeiten wollen.\n\n");
        printf("Ihre Eingabe: ");
        scanf("%i",&file);
        printf("\n\n\n");
    
        switch(file)
        {
        case 1:  printf("********** Airplus **********\n");
    
    	input_stream  = fopen( INPUTFILE, "r"); // Eingabe oeffnen (lesen)
    	if (input_stream == NULL)  //bei nicht vorhandener datei...
        {
    		printf( "\nThe file '%s' was not opened\n", INPUTFILE );//fehlermeldung
    		exit(2);
    	};
    
    	output_stream =  fopen( OUTPUTFILE, "a"); //Ausgabe oeffnen (anhängen)
    	if (output_stream == NULL) //bei nicht vorhandener datei...
        {
    		printf( "\nThe file '%s' was not opened\n", OUTPUTFILE );//fehlermeldung
    		exit(2);
    	};
    
    	while (!feof(input_stream)) //Solange kein End-Of-File in der Eingabe...
        { 
    		fgets (line, BUFSIZ, input_stream); //<-- ?
    
    		i = 0;
    		temptok = line; //<-- ?
    		while ( (tokens[i] = strtok(temptok, DELIM)) != NULL) //strtok erwartet folgende Parameter:
    //temptok ist die zu splittende Zeile beim 1. Aufruf und NULL bei nachfolgenden Aufrufen;
    //der zweite Parameter sind die Grenzen der Tokens
    // Konstante DELIM oben auf ";" definiert
    //strtok gibt einen Zeiger auf den nächsten Token zurück oder NULL, wenn kein Token mehr da ist 
    //(String zu Ende tokenisiert)
    
    //weise tokens[i] die Adresse des nächstens Tokens zu; wenn die Adresse nicht NULL ist, mache Folgendes: ...
            {
    			temptok = NULL;
    			i++;
    		};
    
    		//schreiben in datei
    		fprintf (output_stream, "\n%s;",tokens[3]);
    		fprintf (output_stream, "%s;",tokens[4]);
    		fprintf (output_stream, "%s;",tokens[5]);
    		fprintf (output_stream, "%s;",tokens[13]);
    		fprintf (output_stream, "%s;",tokens[17]);
    		fprintf (output_stream, "%s;",tokens[18]);
    		fprintf (output_stream, "%s;",tokens[19]);
    		fprintf (output_stream, "%s;",tokens[25]);
    		fprintf (output_stream, "%s;",tokens[27]);
    		fprintf (output_stream, "%s;",tokens[31]);
    		fprintf (output_stream, "%s;",tokens[38]);
    	};
    	//schließen der beiden datein
    	fclose (output_stream);
    	fclose (input_stream);
    
    	break;
       case 2:  printf("********** Vodafone **********\n");
                  break;
       case 3:  printf("********** Programm wird beendet **********\n");
                  break;
       default :  printf("********** Falsche Eingabe! **********\n");
                  break;
    }	
    system("pause");
    
    }
    

    AJ, kannst du das programm nachvollziehen und evtl kommentare dazu schreiben, was genau in den einzelnen zeilen passiert? ich verlier wiedermal den überblick 🙄

    hab nun das, wo ich wirklich mir nicht viel bei denken kann mit "//<-- ?" beschrieben



  • OK 🙂

    #include <stdio.h>
    
    #include <string.h>
    
    #define INPUTFILE "Air_Plus_Beispiel.csv" //inputfile wird definiert
    #define OUTPUTFILE "test.csv" //outputfile wird definiert
    #define DELIM ";" //ab ; neu
    
    int main (void) {
    	FILE * input_stream, *output_stream;  //Dateizeiger, zeigt auf Informationen über eine geöffnete Datei (nach fopen())
    	char line[BUFSIZ];  //Speicherbereich für eingelesene Zeile
    	char *tokens[BUFSIZ]; //Zeigerarray zum Speichern der Zeiger auf die einzelnen Tokens
    	int i;
    	char * temptok;  //Hilfszeiger für strtok()
    	char file;
    
    	printf("********** Datei-Auswahl **********\n\n");
        printf("1. Airplus\n");
        printf("2. Vodafone\n");
        printf("3. Beenden\n\n");
    
        printf("Bitte waehlen Sie nun, welche Datei sie verarbeiten wollen.\n\n");
        printf("Ihre Eingabe: ");
        scanf("%i",&file);
        printf("\n\n\n");
    
        switch(file)
        {
        case 1:  printf("********** Airplus **********\n");
    
    	input_stream  = fopen( INPUTFILE, "r"); // Eingabe oeffnen (lesen)
    	if (input_stream == NULL)  //bei nicht vorhandener datei...
        {
    		printf( "\nThe file '%s' was not opened\n", INPUTFILE );//fehlermeldung
    		exit(2);
    	};
    
    	output_stream =  fopen( OUTPUTFILE, "a"); //Ausgabe oeffnen (anhängen)
    	if (output_stream == NULL) //bei nicht vorhandener datei...
        {
    		printf( "\nThe file '%s' was not opened\n", OUTPUTFILE );//fehlermeldung
    		exit(2);
    	};
    
    	while (!feof(input_stream)) //Solange kein End-Of-File in der Eingabe...
        { 
    		fgets (line, BUFSIZ, input_stream); //liest eine Zeile von einer Datei ein
    
    		i = 0;
    		temptok = line; //weißt die gespeicherte Adresse in line auf temptok zu; temptok zeigt somit auf die gleiche Adresse wie line
    		while ( (tokens[i] = strtok(temptok, DELIM)) != NULL) //strtok erwartet folgende Parameter:
    //temptok ist die zu splittende Zeile beim 1. Aufruf und NULL bei nachfolgenden Aufrufen;
    //der zweite Parameter sind die Grenzen der Tokens
    // Konstante DELIM oben auf ";" definiert
    //strtok gibt einen Zeiger auf den nächsten Token zurück oder NULL, wenn kein Token mehr da ist 
    //(String zu Ende tokenisiert)
    
    //weise tokens[i] die Adresse des nächstens Tokens zu; wenn die Adresse nicht NULL ist, mache Folgendes: ...
            {
    			temptok = NULL;
    			i++;
    		};
    
    		//schreiben in datei
    		fprintf (output_stream, "\n%s;",tokens[3]);
    		fprintf (output_stream, "%s;",tokens[4]);
    		fprintf (output_stream, "%s;",tokens[5]);
    		fprintf (output_stream, "%s;",tokens[13]);
    		fprintf (output_stream, "%s;",tokens[17]);
    		fprintf (output_stream, "%s;",tokens[18]);
    		fprintf (output_stream, "%s;",tokens[19]);
    		fprintf (output_stream, "%s;",tokens[25]);
    		fprintf (output_stream, "%s;",tokens[27]);
    		fprintf (output_stream, "%s;",tokens[31]);
    		fprintf (output_stream, "%s;",tokens[38]);
    	};
    	//schließen der beiden datein
    	fclose (output_stream);
    	fclose (input_stream);
    
    	break;
       case 2:  printf("********** Vodafone **********\n");
                  break;
       case 3:  printf("********** Programm wird beendet **********\n");
                  break;
       default :  printf("********** Falsche Eingabe! **********\n");
                  break;
    }	
    system("pause");
    
    }
    

    Funktioniert dein Programm eigentlich fehlerfrei? Zumindest an einer Stelle dürfte was falsch laufen. Schau dir mal deine Ausgabedatei an, speziell die letzten zwei Zeilen.



  • ja, so ganz funktioniert es noch nicht 😕
    beim schreiben in die neue datei kommen ein paar sachen ein wenig "komisch" an *grübel*



  • Also ein Fehler liegt schon mal daran, dass du den Rückgabewert von fgets() nicht überprüfst. Auch wenn fgets() die letzte Zeile in der Datei gelesen hat, erkennt feof() noch nicht, dass das Dateiende erreicht wurde. Erst wenn das Dateiende "gelesen" wird. Und in dem Fall liefert fgets() 0 zurück. Du musst also den Rückgabewert von fgets() abprüfen, ob er ungleich 0 ist. Wenn ja, dann soll der Code darunter ausgeführt werden, wenn nein, dann nicht.

    Dann kommt es mir noch mit dem tokens Array komisch vor. Daraus solltest du am besten ein zweidimensionales Array machen:

    char tokens[ANZ_SPALTEN][BUFSIZ];
    

    Zusätzlich brauchst du dann noch einen Zeiger wie temptok (aber nicht temptok selber benutzen).

    Den Rückgabewert von strtok weißt du dann auf den neuen Zeiger zu und in der Schleife kopierst du per strcpy() den Inhalt auf den der neue Zeiger zeigt in das tokens-array.

    Also so:

    ...
    char tokens[ANZ_SPALTEN][BUFSIZ];
    char *akt_token; //neuer Zeiger, der auf das aktuelle Token zeigt
    ...
    for(i = 0; (akt_token = strtok(temptok, DELIM)) != NULL && i < ANZ_SPALTEN; ++i)
    {
       strcpy(tokens[i], akt_token);
       temptok = NULL;
    }
    ...
    


  • und wo genau muss ich

    for(i = 0; (akt_token = strtok(temptok, DELIM)) != NULL && i < ANZ_SPALTEN; ++i) 
    { 
       strcpy(tokens[i], akt_token); 
       temptok = NULL; 
    }
    

    jetzt einsetzen? 😕



  • wird das mit dem 2 dimensionalen array nicht viel komplizierter für mich?

    oder muss ich wirklich NICHTS weiter ändern im code, außer was du mir geschrieben hattest?



  • AJ schrieb:

    OK 🙂

    Funktioniert dein Programm eigentlich fehlerfrei? Zumindest an einer Stelle dürfte was falsch laufen. Schau dir mal deine Ausgabedatei an, speziell die letzten zwei Zeilen.

    was genau meintest du damit?



  • Troja2k schrieb:

    und wo genau muss ich

    for(i = 0; (akt_token = strtok(temptok, DELIM)) != NULL && i < ANZ_SPALTEN; ++i) 
    { 
       strcpy(tokens[i], akt_token); 
       temptok = NULL; 
    }
    

    jetzt einsetzen? 😕

    Das ersetzt deine bisherige strtok() Schleife

    Troja2k schrieb:

    wird das mit dem 2 dimensionalen array nicht viel komplizierter für mich?

    oder muss ich wirklich NICHTS weiter ändern im code, außer was du mir geschrieben hattest?

    Es wird dadurch nicht wirklich komplizierter, aber auf jeden Fall sicherer.

    Mehr musst du wirklich nicht ändern. Nur eben das behandeln der Daten mit strtok() und die Abfrage vom Rückgabewert von fgets().

    Troja2k schrieb:

    AJ schrieb:

    OK 🙂

    Funktioniert dein Programm eigentlich fehlerfrei? Zumindest an einer Stelle dürfte was falsch laufen. Schau dir mal deine Ausgabedatei an, speziell die letzten zwei Zeilen.

    was genau meintest du damit?

    Normalerweise müssten die zwei letzten Zeilen genau gleich sein und es müsste eine Zeile mehr existieren als in der Quelldatei.

    Wie gesagt erst wenn fgets() (oder eine andere Lesefunktion) das Dateiende auch wirklich gelesen hat, erkennt feof() das Dateiende.
    In deinem Fall würde das heißen, dass du die letzte Zeile einliest (der Dateizeiger steht vor dem Dateiende) und auswertest, dann kommt feof() und erkennt nicht, dass der Dateizeiger schon am Dateiende steht, da das Dateiende noch nicht gelesen wurde. Also wird die Schleife nochmal ausgeführt. fgets() liest nun das Dateiende und gibt 0 als Erkennung eines "Fehlers" zurück. Da du das aber nicht auswertest wird der Quellcode ganz normal weiterverarbeitet, d. h. die zuvor gelesene Zeile wird nochmal fälschlicherweise verarbeitet und erst jetzt erkennt feof(), dass das Dateiende erreicht wurde.


Anmelden zum Antworten