File einlesen und in ein Struct speichern



  • Hallo Zusammen,

    ich habe ein Problem und hoffe darauf, dass mir die Schwarmintelligenz weiterhilft 🙂

    Ich möchte eine .bin.ascii Datei einlesen, die eine große Menge an Datensätzen hat. Die Datensätze sind nur Int - Variablen.

    In den ersten 8 Zeilen habe ich "Header"-Text. Den habe ich vorab heraus genommen.

    Um jetzt auf jede Spalte an sich zugreifen zu können und diese mit einer anderen Datei abgleichen zu können, möchte ich beim einlesen der Werte, den Wert der Spalte in ein Struct speichern und es anschließend in einer zweiten Datei schreiben.

    Mein Problem dabei ist, dass ich den Text nicht in mein Struct gespeichert bekomme.

    Die Datei ist dabei wie folgt aufgebaut...
    3 Leerzeichen, erste Spalte, 3 Leerzeichen, zweite Spalte, 3 Leerzeichen, 4 Spalte usw...

    Folgenden Code habe ich...

    struct Straße
    {
        int satzNr;
        int fstArt;
        int start_nummer;
        int ziel_nummer;
        int lfd_nr;
        int element_index;
    };
    
    int einlesenFile(char *file_arr)
    {
        if(file_arr){
            printf("\n\nFile gelesen!!\n\n");
            FILE *openFile = fopen(file_arr, "r");
            
            //Ausgabevariablen für die einzelnen Teilwerte
            char c;
            int rows = 0;
            char line[8];
            while (!feof(openFile))
            {
                //Initialisierung des structs
                struct Straße zp1;
                
                //Trimme gesamte Dateien um 9 Reihen, sodass nur "Rohe Daten" im 
                //Int- Format vorliegen.
                if (rows < 9)
                {
                    fgets(line,8, openFile);
                    char *p = strchr(line, '\n');
    
                    if (!p) 
                    {
                        fscanf(openFile, "%*[^\n]\n");
                    } else {
                        *p = '\0';
                    }
                    rows++;
                } else if (rows == 9) 
                {
    
                    //Kopieren der Elemente in das Struct 
                    //HIER IST DER WURM DRIN!!
                    //fread(&zp1, sizeof(struct Z_p_fahrstr), 1, openFile);
                    fscanf(openFile, "%d\t%d\t%d\t%d\t%d\t%d\t",&zp1.satzNr, &zp1.fstArt, &zp1.start_nummer, &zp1.ziel_nummer, &zp1.lfd_nr, &zp1.element_index);
                    printf("Number is: %d\n", zp1.satzNr);
    
                   // einfache Ausgabe "klappt"
                    /*c = getc(openFile);
                    printf("   %c",c);*/ 
                    rows++;
                } else 
                {
                    //fscanf(openFile, "%d\t%d\t%d\t%d\t%d\t%d\t",&zp1.satzNr, &zp1.fstArt, &zp1.start_nummer, &zp1.ziel_nummer, &zp1.lfd_nr, &zp1.element_index);
                    //printf("Number is: %d\n", zp1.satzNr);           
                    // einfache Ausgabe "klappt"
                    
                    c = getc(openFile);
                    printf("%c",c); 
                    
                }
            }
            fclose(openFile);
            return EXIT_SUCCESS;
        } else {
            printf("file nicht gelesen");
            return EXIT_FAILURE;
        }
    }
    
    int main(void)
    {
        //Speicherorte Dokumente
        char* file_arr[] = {"C:\\UserData\\computereins\\Documents\\citystrassen.bin.ascii", "C:\\UserData\\computereins\\Documents\\citystrassen2.bin.ascii", };
        
        for (int i = 0; i < 2; i++)
            {
                einlesenFile(file_arr[i]);
            }
        
        return 0;
    }
    

    Danke vorab für eure Hilfe!:)
    Lg.



  • Ich habe deinen Code radikal vereinfacht, und unnütze und falsche Dinge (feof,strchr,getc) entsorgt.
    Das von dir gewünschte Überlesen der Headerzeilen wird auch gleich mit erledigt.
    Das Ablegen der Daten in eine struct-Liste fehlt noch.

    struct Strasse
    {
        int satzNr;
        int fstArt;
        int start_nummer;
        int ziel_nummer;
        int lfd_nr;
        int element_index;
    };
    
    int einlesenFile(char *file_arr)
    {
            FILE *openFile = fopen(file_arr, "r");
            char z[1000];
            struct Strasse zp1;
            
            while( fgets(z,1000,openFile) )
            {
                if( 6==sscanf(z,"%d%d%d%d%d%d",&zp1.satzNr, &zp1.fstArt, &zp1.start_nummer, &zp1.ziel_nummer, &zp1.lfd_nr, &zp1.element_index) )
                    printf("Number is: %d\n", zp1.satzNr);
            }
            
            fclose(openFile);
    }
    


  • @Ashtari sagte in File einlesen und in ein Struct speichern:

    Die Datei ist dabei wie folgt aufgebaut...
    3 Leerzeichen, erste Spalte, 3 Leerzeichen, zweite Spalte, 3 Leerzeichen, 4 Spalte usw...

    Wie wichtig ist es für dich, dass das eingehalten wird? Dürfen auch mal 2 oder gar 4 Leerzeichen vorhanden sein? Können Werte fehlen, sodass du 6 Leerzeichen hintereinander hast? Wenn ja, was ist dann der Wert des int - nan gibt es ja nur bei float. Was soll im Fehlerfall passieren, also wenn z.B. mal ein Wert zu wenig in einer Zeile steht? Die Lösung von @Wutz ignoriert die Anzahl der Leerzeichen (egal ob 1,2,3,4 oder ganz viele, solange die Zeile nicht zu lang wird) und geht überspringt einfach Zeilen, bei denen nicht 6 Zahlen gefunden wurden. Da ich beruflich sehr häufig kaputte Dateien zugeschickt bekomme, würde ich immer irgendwelche Fehlerbehandlungen oder zumidnest Ausgaben wie printf("Zeile %d hat unerwartetes Format\n", zeile) einbauen.



  • @Wutz sagte in File einlesen und in ein Struct speichern:

    Ich habe deinen Code radikal vereinfacht, und unnütze und falsche Dinge (feof,strchr,getc) entsorgt.
    Das von dir gewünschte Überlesen der Headerzeilen wird auch gleich mit erledigt.

    Herzlichen Dank 🙂
    Könntest du mir noch erklären, warum feof, strchr und getc "unnütz oder falsch" sind?

    Zugegeben, was C an geht bin ich recht frisch und unerfahren, das waren aber so die Umsetzungen die ich im Internet gefunden habe.



  • @wob sagte in File einlesen und in ein Struct speichern:

    @Ashtari sagte in File einlesen und in ein Struct speichern:

    Die Datei ist dabei wie folgt aufgebaut...
    3 Leerzeichen, erste Spalte, 3 Leerzeichen, zweite Spalte, 3 Leerzeichen, 4 Spalte usw...

    Wie wichtig ist es für dich, dass das eingehalten wird? Dürfen auch mal 2 oder gar 4 Leerzeichen vorhanden sein? Können Werte fehlen, sodass du 6 Leerzeichen hintereinander hast? Wenn ja, was ist dann der Wert des int - nan gibt es ja nur bei float. Was soll im Fehlerfall passieren, also wenn z.B. mal ein Wert zu wenig in einer Zeile steht? Die Lösung von @Wutz ignoriert die Anzahl der Leerzeichen (egal ob 1,2,3,4 oder ganz viele, solange die Zeile nicht zu lang wird) und geht überspringt einfach Zeilen, bei denen nicht 6 Zahlen gefunden wurden. Da ich beruflich sehr häufig kaputte Dateien zugeschickt bekomme, würde ich immer irgendwelche Fehlerbehandlungen oder zumidnest Ausgaben wie printf("Zeile %d hat unerwartetes Format\n", zeile) einbauen.

    Das Format kann abweichen.. Also wäre die Lösung von Wutz da schon die Richtige.
    Die Fehlerbehandlung wäre dann der nächste Schritt. In C gibt es ja kein (ich nenne es mal) klassisches Exception Handling, sondern ich würde alle auftretenden Probleme mit If-Anweisungen abfangen oder?

    Ich habe viel in Swift und Java entwickelt und da kann man ja recht "einfach" seine Exceptions abfangen und muss nicht jeden Fall berücksichtigen, sondern kann Sonderfälle betrachten und die davon abweichenden Exception einfach als "Allgemeine" Exception betrachten.



  • @Ashtari sagte in File einlesen und in ein Struct speichern:

    Könntest du mir noch erklären, warum feof, strchr und getc "unnütz oder falsch" sind?

    Deine Benutzung von feof war falsch. Dieses hier:

    while (!feof(openFile))

    funktioniert nicht. Dass man am Dateiende ist, erkennt feof erst NACHDEM du versucht hast, über das Ende hinaus zu lesen (außer in Pascal, da ist das anders). Wenn du dich also direkt am Ende befindest, ist das eof noch false, obwohl kein weiteres Zeichen gelesen werden kann.

    Korrekt ist:

    • Versuche zu lesen
    • Teste, ob das Lesen erfolgreich war - wenn ja, dann verarbeiten

    Falsch ist:

    • Teste, ob der Dateistream ok ist
    • Wenn ja, dann lesen & verarbeiten


  • Dieser Beitrag wurde gelöscht!


  • Mal eine weitere Frage zu ähnlichem Problem...

    Ich möchte jetzt ein .bin.ascii File mit ähnlichem Aufbau, aber anderem Inhalt einlesen.

    Die File hat den Aufbau ( | ist der Trenner der Spalte):
    Nummer | Name | anzahl vorhanden |anzahl benötigt
    1 | 'Getraenk Fanta' | 0 | 12

    Dabei ist der Name immer innerhalb zwei Hochkommata und die Beschreibung des Produkts (also Getraenk zB. oder Alkohol usw.) mit zwei Leerzeichen zum Produktnamen getrennt.

    Nummer ist ein Integer Wert (von 1 bis < 2000), Name ist, so vermute ich, ein char, anzahl vorhanden und anzahl benötigt wieder Integer Werte, beide können dreistellig werden (also < 999).

    Das Ganze möchte ich in folgendem Struct speichern...

    struct getraenk
    {
        int nummer;
        char nameGetraenk[100];
        int anzahlVorhanden;
        int anzahlBenoetigt;
    };
    

    Jetzt habe ich es, ähnlich wie oben gemacht..

    #define BUFFER 100
    ...
    int einlesenGetraenkeListe(char *file_arr)
    {
        FILE *openFile = fopen(file_arr, "r");
        char z(BUFFER);
        struct getraenk getraenk1;
    
        while(fgets(z, BUFFER, openFile))
        {
            if (4 == sscanf(z, "%d %s %d %d", &getraenk1.nummer, getraenk1.nameGetraenk, &getraenk1.anzahlVorhanden, &getraenk1.anzahlBenoetigt))
            {
                printf("Getraenkename ist: %d\n", getraenk1.nameGetraenk);
            }
        }
    }
    

    Die Ausgabe klappt dabei aber nicht so.. Nehme ich das o.g. Beispiel (...sscanf(z, "%d %s %d ....)) erhalte ich keine Ausgabe..
    Wenn ich jetzt aber das s in ein d ändere, also als signed int anzeigen lasse, dann erhalte ich einen output (in jeder Zeile 6422028...)

    Ich verstehe nicht ganz wo der Fehler liegt, denn mit dem ersten Struct hat es wunderbar funktioniert und nach dem gleichen (naja, ähnlichem - ich habe ja ein char in meinem struct was ich jetzt mit "zuordnen" möchte) Muster geht es jetzt nicht.

    Herzlichen Dank für eure Hilfe vorab.



  • @Ashtari Sind da wirklich runde Klammern in Zeile 6?

    Sind in der Datei die | enthalten oder hast du das nur für uns gemacht?

    scanf überliest bei %s führende Leerzeichen und dann weiter bis zum nächsten Leerzeichen.
    Da wäre '%[^']' statt des %s nötig. (vor dem ersten ' ist noch ein Leerzeichen)

    Du kannst auch mal z ausgeben.



  • int einlesenGetraenkeListe(const char *file_arr)
    {
        FILE *openFile = fopen(file_arr, "r");
        char z[BUFFER];
        struct getraenk getraenk1;
    
        while(fgets(z, BUFFER, openFile))
        {
            if (4 == sscanf(z, "%d%*[^']'%[^']'%*s%d%*s%d", &getraenk1.nummer, getraenk1.nameGetraenk, &getraenk1.anzahlVorhanden, &getraenk1.anzahlBenoetigt))
            {
                printf("Getraenkename ist: %s\n", getraenk1.nameGetraenk);
            }
        }
        fclose(openFile);
    }
    


  • Hallo @DirkB , Hallo @Wutz ,

    danke für eure Hilfe - mit der Lösung von Wutz hat es hin gehauen.

    Ein - %[^']' - bewirkt dann quasi, dass Leerzeichen vor dem Hochkommata "übersprungen" werden?



  • @Ashtari sagte in File einlesen und in ein Struct speichern:

    Hallo @DirkB , Hallo @Wutz ,

    Ein - %[^']' - bewirkt dann quasi, dass Leerzeichen vor dem Hochkommata "übersprungen" werden?

    Nein, das bewirkt schon ein Leerzeichen im Formatstring
    %[^'] Liest alles, bis auf ' ein. (Das ^ schließt Zeichen aus)
    Es wird also Alles bis auf das Hochkomme eingelesen. Deswegen steht es dahinter nochmal.

    danke für eure Hilfe - mit der Lösung von Wutz hat es hin gehauen.

    Ich sehe da Probleme, wenn zwischen den | und den Zahlen kein Leerzeichen (oder ähnliches) ist.



  • @DirkB sagte in File einlesen und in ein Struct speichern:

    danke für eure Hilfe - mit der Lösung von Wutz hat es hin gehauen.

    Ich sehe da Probleme, wenn zwischen den | und den Zahlen kein Leerzeichen (oder ähnliches) ist.

    Sorry, hatte vergessen oben auf deine Fragen zu antworten.
    Die Spalten sind mit Leerzeichen getrennt - ich hatte es in der Frage nur als optischen Trenner genutzt damit ihr es besser erkennen könnt.. Führte dann am Ende wohl eher zu Verwirrungen.

    Die Daten werden getrennt durch Leerzeichen, sodass eine Zeile dann ungefähr so aussieht...

    123 'Getraenk Cola' 0 12
    (Edit: bekomme keine weiteren Leerzeichen dazwischen, es sind aber zwischen 2 und 5 Leerzeichen zwischen den Spalten)

    Mit deiner Erklärung zu %[^'] sollte es also klappen, da es den Text, ausgenommen der Hochkommata einliest, bis zu dem nächsten Leerzeichen.

    Danke nochmals und schöne Ostertage 🙂


  • Mod

    @Ashtari sagte in File einlesen und in ein Struct speichern:

    Ein - %[^']' - bewirkt dann quasi, dass Leerzeichen vor dem Hochkommata "übersprungen" werden?

    Nein, überhaupt nicht. Lies die Erklärungen und die Anleitung! scanf sollte man als C-Programmierer schon halbwegs beherrschen.

    Erstmal kann das kein Ausdruck zum Überspringen von irgendwas sein, denn da steht ein Prozentzeichen und das ist für scanf der Trigger, dass da auch tatsächlich etwas gelesen und in einer Variablen gespeichert werden soll. Was das ist, dafür müssen wir die Bedeutung des nächsten Zeichens nachgucken, also [. Da steht in der Anleitung zwar etwas vonwegen, dass dies ein Scanset wäre, aber da wir die Anleitung ja hoffentlich gründlich gelesen haben, wissen wir, dass hier ein Sonderfall vorliegt, weil das übernächste Zeichen ein ^ ist, und wir daher ein negiertes Scanset haben. Also wird eine Zeichenkette gelesen, die alles außer dem enthält, was zwischen [^ und ] steht. Also hier alles außer einem Hochkomma. Und das war dann das, worauf das % sich bezog. Das nächste Zeichen, ebenfalls ein Hochkomma gehört dann schon nicht mehr zu dem Prozentausdruck, gibt also Zeichen an, die überlesen werden sollen, ohne sie irgendwo zu speichern. Es soll hier also das Hochkomma übersprungen werden, bei dem das vorher negierte Scanset gestoppt hat.

    PS: Wie tippe ich im Forum eigentlich ein einzelnes Hochkomma in Code-Formatierung? Drei Hochkommata nacheinander bringen die Formatierung komplett durcheinander, und auch mit Backslashes habe ich keine funktionierende Variante gefunden



  • Dieser Beitrag wurde gelöscht!

Anmelden zum Antworten