Textdatei lesen und in Structur speichern



  • Hy Leute,

    ich muss in den nächsten 2 Wochen eine Programm schreiben, welches Daten einliest und dann je nach Wunsch auflistet.

    Ich hab schon bei ersterem Probleme. Hab wenig Praxiserfahrung und schaue schon eine gefühlte Ewigkeit in den schlechten Skripten und in Haufenweise Literatur.
    Er liest auch was aus, jedoch nur Mist.

    Die Tex-Datei wurde so vorgegeben. Bin mir also nicht sicher, ob ich sie anpassen darf?!

    Ich "programmiere" mit Xcode unter OS X.

    Kann mir bitte jemand von euch helfen?

    Meine TXT-Datei "Liste.txt":

    Name: Meier
    Vorname : Hans
    Alter: 55
    Jahreseinkommen:  100.000000
    
    Name: Klein
    Vorname : Jutta
    Alter: 22
    Jahreseinkommen:  20000.22
    
    Name: Kurz
    Vorname : Jürgen
    Alter: 37
    Jahreseinkommen:  554.700012
    

    Mein Code:

    #include <stdio.h>
    #include <stdlib.h>
    
    struct satz {
        char  name[21];
        char  vorname[21];
        int  alter;
        float lohn;}__attribute__ ((packed));
    
    int main(int argc, const char * argv[]){
    
        struct satz lib [3];
    
        FILE *Dateiptr;
        int i=1;
        char *ausdatei= "/Name/Liste.txt";
    
        if (!(Dateiptr = fopen(ausdatei,"r")))
        {
            printf("Fehler beim Oeffnen der Datei %s!\n", ausdatei);
            return(-1);
        }
        else
    
            while (fread(&lib[i], sizeof(lib[i]),1, Dateiptr) == 1)
            {
                printf("Datei-Eintrag Nr.%d",i++);
                printf("\n");
                printf("%s",lib[i].name);
                printf("\n");
                printf("%s",lib[i].vorname);
                printf("\n");
                printf("%d",lib[i].alter);
                printf("\n");
                printf("%f",lib[i].lohn);
                printf("\n\n");
    
                i++;
    
            }
        fclose(Dateiptr);
        return(0);
    }
    

    Entschuldigt, falls der ganze Code Mist ist. Hab ihn mir aus mehreren Sachen zusammengesucht.



  • fread ist zum lesen von binären Daten da. Die müssen so wie sie im Speicher liegen in der Datei gespeichert sein.

    Du hast aber eine Textdatei. Dort liegen die Daten menschenlesbar.

    Du brauchst die Funktion fscanf oder fgets und sscanf

    Bei Geldbeträgen rechnet man besser in Cent und nimmt dafür int



  • Wenn nicht weißt was er macht ist zusammengesucht ganz schlecht. Nicht wild rumprobieren, stattdessen nachlesen.

    Die textdatei (nein ich gehe davonaus dass du sie NICHT ändern darfst) liegt in einem speziellen format vor. D.h. zu musst dieses beim auslesen auch berücksichtigen.

    Bedeutet:

    • Struct anlegen
    • Zeile einlesen
    • Doppelpunkt suchen, rechten wert (leerzeichen weggelassen) in die struct kopieren
    • Zeile eilesen
    • Doppelpunkt suchen, rechten wert (leerzeichen weggelassen) in die struct kopieren
    • Zeile eilesen
    • Doppelpunkt suchen, rechten wert (leerzeichen weggelassen) in zahl umwandeln und in die struct kopieren
    • Zeile eilesen
    • Doppelpunkt suchen, rechten wert (leerzeichen weggelassen) in zahl umwandeln und in die struct kopieren
    • eintrag beendet, leere zeile einlesen, wegwerfen und von vorne beginnen

    @DirkB
    Stimmt schon, aber laut Aufgabe soll es wohl float sein. Und auch wenn die Aufgebenstellung noch so dumm ist sollte man sich dran halten damit es keine Probleme gibt... 😞



  • Danke schon einmal für die Tipps.

    Ich kann auch eine ganze Zeile mit fgets einlesen, aber wie schreibe ich das in eine Schleife?

    Also Zeile lesen -> in Struct schreiben -> nächste Zeile lesen

    Ich hab auch ein Problem mit den Strukturen.

    Wie soll ich dem Programm sagen, ob er die gelesene Zeile in Name oder Alter schreiben soll?
    Muss ich dabei immer den linken Teil auslesen und dann sagen Wenn Linke-Seite = Name, dann schreibe in lib.name?

    Mit welchen Funktionen findet man ein Doppelpunkt?

    @DirkB
    Stimmt schon, aber laut Aufgabe soll es wohl float sein. Und auch wenn die Aufgebenstellung noch so dumm ist sollte man sich dran halten damit es keine Probleme gibt...

    Ich würde es auch lieber anders gestalten. Die Struktur und die TXT ist vorgegeben. Den Rest sollen wir uns selber "ausdenken".

    Danke schon mal für die Tipps?



  • Ich kann auch eine ganze Zeile mit fgets einlesen, aber wie schreibe ich das in eine Schleife?

    Ähhh indem dus einfach in die geschweifen klammern der Schleife steckst ?

    Muss ich dabei immer den linken Teil auslesen und dann sagen Wenn Linke-Seite = Name, dann schreibe in lib.name?

    Nö. Du schreibst einfach in die Schleife 4 mal fgets. Beim ersten dann in Namen schreiben, beim 2. in Vornamen, usw.

    Pseudocode:

    satz person;
    //person ausnullen
    char line[100];
    fgets(line, 100, file);
    char*pointerToAfterDot = strchr(line, ':') + 1;
    strcpy (person.name, pointerToAfterDot) // namen  einlesen
    


  • satz person;
    //person ausnullen
    char line[100];
    fgets(line, 100, file);
    char*pointerToAfterDot = strchr(line, ':') + 1;
    strcpy (person.name, pointerToAfterDot) // namen einlesen

    Das funktioniert ganz gut. Jetzt versuche ich den Code so anzupassen, bis alle Daten drin sind.

    Schon mal vielen Dank. 🙂

    EDIT:
    Nur eine Sache habe ich noch:
    Damit kann man ja die Characters einlesen.

    Wie sieht das mit Integer oder Float-Werten aus?
    Ich kann es mit deiner Methode auch so einlesen...als String.
    Vielleicht reicht das ja.



  • Zum umwandeln von Text in Zahlenwerte, gibt es die Funktionen strtol (STRing TO Long) und strtod (STRing TO Double).
    ^(Es gibt auch noch ein paar andere mehr. Hängt auch vom verwendeten C-Standard ab.)^

    Du kannst auch sscanf dafür nehmen.

    Bemme90 schrieb:

    strcpy (person.name, pointerToAfterDot) // namen einlesen
    

    Achte auf die Länge vom Namen.
    Du hast in deiner struct nur begrenzt Platz (20 Zeichen). Wenn du zuviel kopierst, werden andere Daten überschrieben.



  • Die Alternative mit sscanf schau ich mir dann noch mal an.

    Ich hab aber jetzt noch wegen 2 Sachen Bauchschmerzen:

    1. Ich führe die ganze Sache zur Zeit 3 Mal aus, weil es genau 3 Datensätze sind.
    Das ist mir aber zu unflexibel. Es wäre ja möglich, dass ein neuer Eintrag hinzukommt.
    Kann man das auch irgendwie so gestalten, bis er ans EOF angelangt ist?

    2. Zwischen den Datensätzen besteht eine Leerzeile. Ich überspringe die momentan, indem ich die Zeile lese, aber nirgends speichere.
    Kann man eine Leerzeile ebenfalls abfangen?
    Wenn Zeile Leer, dann mache nichts?

    Hier mal mein bisheriger kompletter Code:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    struct satz {
        char  name[21];
        char  vorname[21];
        char  alter[21];
        char  lohn[21];}__attribute__ ((packed));
    
    int main(int argc, const char * argv[]){
    
        char text[100];
        int i = 0;
    
        struct satz lib[3];
    
        FILE *Dateiptr;
    
        char *ausdatei= "Liste.txt";
    
        if (!(Dateiptr = fopen(ausdatei,"r")))
        {
            printf("Fehler beim Oeffnen der Datei %s!\n", ausdatei);
            return(-1);
        }
        else
    
            while(i<3) {
                fgets(text, 100, Dateiptr);
                char*pointerToAfterDot1 = strchr(text, ':') + 1;
                strcpy (lib[i].name, pointerToAfterDot1); // namen  einlesen
    
                fgets(text, 100, Dateiptr);
                char*pointerToAfterDot2 = strchr(text, ':') + 1;
                strcpy (lib[i].vorname, pointerToAfterDot2); // namen  einlesen
    
                fgets(text, 100, Dateiptr);
                char*pointerToAfterDot3 = strchr(text, ':') + 1;
                strcpy (lib[i].alter, pointerToAfterDot3); // namen  einlesen
    
                fgets(text, 100, Dateiptr);
                char*pointerToAfterDot4 = strchr(text, ':') + 1;
                strcpy (lib[i].lohn, pointerToAfterDot4); // namen  einlesen
    
         fgets(text, 100, Dateiptr);
    
        printf("%s",lib[i].name);
        printf("%s",lib[i].vorname);
        printf("%s",lib[i].alter);
        printf("%s",lib[i].lohn);
        printf("\n");
    
                i++;
            }
    
        fclose(Dateiptr);
        return(0);
    }
    


  • Kann man alles machen.
    Die Frage ist nur, wie viel Aufwand du treiben willst.

    Zu 1. Schau dir mal die Funktionsbeschreibung für fgets genau an. Speziell den Rückggabewert.
    Kannst du hier machen: http://www.cplusplus.com/reference/cstdio/fgets/. Da ist auch ein Beispiel.
    Dein Array lib musst du dann auch größer (flexibel) machen.

    Zu 2. Du hast eine definierte Reihenfolge (Name, Vorname, Alter, Einkommen) der Daten.
    Wenn jetzt keine Leerzeile in der Datei ist, hast du die Daten schon gelesen. Wohin damit?
    Zudem ist die Leerzeile auch ein Trenner zwischen den Datensätzen.

    Du kannst auch eine Zeile einlesen und anhand des Tags (der Text vor dem : ) entscheiden, was eingelesen wurde und entsprechen ablegen. Wenn die Zeile leer* ist, machst du deas i++.
    Ist eben mehr Aufwand.

    *Eine Leerzeile enthält zumindest das '\n'. Sie kann aber auch noch Leerzeichen und Tabulatoren (sog. Whitespace) enthalten.

    Bei deinem Programm wird das Leerzeichen zwischen : und dein Einträgen mit abgespeichert.
    Zudem legst du das '\n' vom Zeilenende auch mit ab.
    Der Name ist dann nicht "Meier" sondern " Meier\n"


Anmelden zum Antworten