Aus Datei daten in Struktur einlesen



  • Das funktioniert nicht, weil du nur .nr und .bezeichnung (aber nicht .name und .preis) einliest.

    scanf überliest Whitespaces (Leerzeichen,Tabulatoren und Zeilenvorschub).
    Du kommst also ganz automatisch in die nächste Zeile.

    for (i=1;i<*anz;i++){ // statt <=n-1 nimmt man <n
            fscanf(datei, "%i%s%s%lf",i, &Artikel[i].nr, Artikel[i].bezeichnung, Artikel[i].name, &Artikel[i].preis);
        }
    

    ⚠ Sobald Leerzeichen in Name oder BEzeichnung sind, funktioniert das so nicht mehr, da %s nur bis zu einem Whitespace liest.



  • habe meine Funktion mal angepasst
    meine denke ist jetzt, in der Ersten Zeile steht der Kopf den brauch ich nicht, deswegen lese ich diesen in die Variable dumpcahr.
    dann geht es mit den Daten weiter in der Ersten spalte steht nur eine Fortlaufende Nummer --> brauch ich auch nicht --> dumpint

    fscanf(datei,"%s\t%s\t%s\t%s\t%s",&dumpchar,&dumpchar,&dumpchar,&dumpchar,&dumpchar);
            for (i=1;i<=*anz-1;i++){
            fscanf(datei,"%i\t%i\t%s\t%s\t%lf",&dumpint,&Artikel[i].nr,Artikel[i].bezeichnung,Artikel[i].name,&Artikel[i].preis);
    

    Leider liefert auch diese Funktion nur Müll zwar immer den Selben aber nichts was meinen Daten ähnlich sieht.
    so sieht das txt ursprünglich aus, alles schön tabstop getrennt

    Nummer	Artikelnummer	Artikelname	Hersteller	Preis
    1	2	Baum	Wald	12.47
    2	3	Rot	Farbe	1123.52
    3	4	Leder	Kuh	14.77
    4	5	Kirsche	Garten	15.98
    5	6	Hammer	Nagel	16.45
    6	7	Rababerkompott	Kueche	1.25
    7	8	Katzenfutter	Wiskas	4.99
    8	9	Hundefutter	Schappie	4.99
    9	10	Kopfhoerer	Musik	2.99
    10	11	Tasse	Willory and Borch	24.99
    11	12	Fueller	Lamy	19.95
    12	13	Rechenschieber	Reis	29.80
    

    und so wenn ich es mit meiner Funktion einlese (Die Kopfzeile kommt dabei von meinem Programm und nicht aus der Datei diese wird also nicht korreckt eingelesen)

    Nummer	ArtNummer	Artikelname	     Hersteller		  Preis
    
    1       0               �@��                 �@���>���@��(���  0.00   
    2       15133198                             ELF              0.00   
    3       52              |g                                      0.00   
    4       4                                                       0.00   
    5       1386748         �(                  �1                  0.00   
    6       1396092         |M                                      0.00   
    7       4                                                      0.00   
    8       1291452         ,3                                        0.00   
    9       1685382482      �1                  lB��                 0.00   
    10      0                                    6(�                  0.00
    

    grüße



  • Zeig mehr Code.
    Ein kleines Programm, dass man compilieren kann und den Fehler zeigt.
    Mit allen Definitionen und Deklarationen die nötig sind.



  • Mein Programm auseinander pflücken würde zu lange dauern, das sind insgesammt 650 Zeilen Code.

    hier mal der gesamte Quellcode die Funktionen um die es geht stehen bei bei Zeile 300 bis 340

    wenn man den Fehler reproduzieren will muss man als erstes Testdaten erzeugen und diese dann speichern (wird elber Ordner wie die ausführbare Datei)
    - Daten Testdaten erzeugen
    - Dateisystem/ Daten Speichern
    danach startet man das Programm nochmal neu und geht in den Menüpunkt Dateisystem und dort dann auf Datei Öffnen Wichtig ist das vorher keine Testdaten erzeugt wurden

    Achtung nicht verwirren lassen da kommt ein fenster bei dem man seine Handy nummer angeben soll --> wegklicken
    dann muss man ca. ne Minute warten und ein Capcha lösen
    http://depositfiles.com/files/32kt0emi4

    Bitte schlagt mich nicht zu sehr, ich bin erst anfänger und habe noch nicht so viel Programmiert. Ich weiß das mein Code mieß ist.



  • RajHid schrieb:

    Achtung nicht verwirren lassen da kommt ein fenster bei dem man seine Handy nummer angeben soll --> wegklicken
    dann muss man ca. ne Minute warten und ein Capcha lösen

    Danke für die Warnung.

    Wenn dein Problem in den 40 Zeilen ist dann kannst du es auch zusammenkürzen.
    http://www.c-plusplus.net/forum/136013



  • Hier mal ein Beispiel, wie du dein Problem auf das wesentliche zusammen stauchen kannst:

    #include <stdio.h>
    #include <conio.h>
    
    struct Artikel
    {
        int dumpint;
        int nr;
        char bezeichnung[20];
        char name[20];
        double preis;
    } art;
    
    FILE *datei ;
    
    int lesen()
    {
        char header[80];
        int satz;
        datei=fopen("katalog.data","r+");
        printf("===================================================\n\n");
        for( int i = 0; i < 5; i++)
            fscanf(datei,"%s ", header);
        while(!feof(datei))
        {
            satz = fscanf(datei," %i %i %s %s %lf", &art.dumpint, &art.nr, art.bezeichnung, art.name, &art.preis);
            printf("%i %s %s %.2f\n", art.nr, art.bezeichnung, art.name, art.preis);
    
            printf("%d\n", satz);   // zur Kontrolle für fscanf
        }
        fclose(datei);
    
        printf("Weiter mit beliebiger Taste...");
        getch();
    
        return 0;
    }
    
    int main()
    {
        lesen();
    }
    

    Das entspricht aber nicht der von dir geforderten Lösung!

    Und dieses Beispiel könnte man noch kürzer fassen.

    Mit den Änderungen für deinen speziellen Fall sollte das etwa die gleiche Zeilenzahl werden.

    Irgend welche Hoster wo Handynummern oder sonstiges gefordert wird werden hier nur die wenigsten öffnen. Und Zeit in der Warteschleife fördert die Lesebereitschaft auch nicht gerade.

    Wenn dein Quelltext halbwegs übersichtlich geschrieben sein sollte, sollten die maximal 50 Zeilen und dein Problem komplett hier zu zeigen, kein Problem sein.



  • Da ist viel laienhafter Kram bei:
    - globale Variablen
    - unnötiges C99
    - redundante Leerzeichen in Formatstrings
    - kein Fehlerbehandlung für Dateilesefehler
    - keine Stringüberlaufprüfung
    - fehlerhaft für Stringwerte mit Whitespaces
    - unportabel wegen conio.h
    - kein Speichern in Array

    #define MAXDS 20
    
    int main()
    {
      struct Artikel
      {
        int dumpint;
        int nr;
        char bezeichnung[100];
        char name[100];
        double preis;
      } art[MAXDS];
      int i=0;
      char zeile[100];
      FILE *f = fopen("daten.txt","r");
      while( i<MAXDS && fgets(zeile,100,f) )
        if( 5==sscanf(zeile,"%d%d%99s%99[^+-0-9]%lf",&art[i].dumpint,&art[i].nr,art[i].bezeichnung,art[i].name,&art[i].preis) )
          ++i;
      fclose(f);
      while( i-- )
        printf("%3d%3d%20s%30s%f\n",art[i].dumpint,art[i].nr,art[i].bezeichnung,art[i].name,art[i].preis);
      return 0;
    }
    

    Das Problem sind die offensichtlich möglichen Stringwerte mit Leerzeichen "Willory and Borch" für Hersteller, sollen die auch für Artikelname möglich sein, hast du ein größeres Problem bei der Zuordnung, da du keine Feldtrennzeichen verwendest.



  • Wutz schrieb:

    Das Problem sind die offensichtlich möglichen Sttringwerte mit Leerzeichen "Willory and Borch" für Hersteller, sollen die auch für Artikelname möglich sein, hast du ein größeres Problem bei der Zuordnung, da du keine Feldtrennzeichen verwendest.

    Na hoffentlich hat er das jetzt verstanden.



  • Danke für eure Hilfe bei mir funktioniert das Einlesen jetz,
    @ Wutz

    kannst du die Zeile

    if( 5==sscanf(zeile,"%d%d%99s%99[^+-0-9]%lf",&art[i].dumpint,&art[i].nr,art[i].bezeichnung,art[i].name,&art[i].preis) )
    

    mal bitte erklären? vor allem die Platzhalter interessieren mich (%d%d%99s%99[^+-0-9]%lf), da scheint man ja eine menge mit anstellen zu können kann man das irgendwo nachlesen, nach was muss ich dafür suchen?.

    Was ich noch erwähnen sollte ich benutze Linux als basissystem
    ZUdem hatte ich noch etliche feheler in meinem Programm.
    Erstmal hab ich versucht mit einem Falschen Dateinamen die Datei mit den Daten zu öffnen.
    zweitens scheint die fscanf Funktion so zu funktionieren dass diese keine Daten in die Strucktur schreibt wenn die Platzhalter nicht stimmen.



  • if( 5==sscanf(zeile,"%d%d%99s%99[^+-0-9]%lf",&art[i].dumpint,&art[i].nr,art[i].bezeichnung,art[i].name,&art[i].preis) )
    

    OK, ich versuche es mal, ist aber sehr viel Tipparbeit, ich hoffe es ohne Fingerkrampf hinzubekommen
    - %d Integerliteral wird versucht zu lesen, führende Whitespaces werden übergangen, Verarbeitung stoppt am ersten nicht zum Integerliteral passendem Zeichen
    - %d Integerliteral wird versucht zu lesen, führende Whitespaces werden übergangen, Verarbeitung stoppt am ersten nicht zum Integerliteral passendem Zeichen
    - %99s eine Zeichenfolge wird versucht zu lesen bis ein Whitespace vorkommt oder 99 Zeichen erreicht wurden, führende Whitespaces werden übergangen
    - %99[^+-0-9] eine Zeichenfolge wird versucht zu lesen bis '+','-' oder '0'..'9' vorkommt oder 99 Zeichen erreicht wurden
    - %lf ein Fließkommaliteral wird versucht zu lesen, führende Whitespaces werden übergangen

    Rückgabewert von sscanf wie auch von fscanf ist die Anzahl der erfolgreich abgearbeiteten Formatspezifizierer. Wurde ein Format nicht richtig erkannt, wird die gesamte Verarbeitung beendet.

    Was ich noch erwähnen sollte ich benutze Linux als basissystem

    fgets+sscanf+fscanf+... ist C89, also portabel, d.h. OS-unabhängig (das ist ja gerade ein wesentlicher Vorteil von Standard C)

    ZUdem hatte ich noch etliche feheler in meinem Programm.

    soll vorkommen, u.a. auch bei Anfängern

    Erstmal hab ich versucht mit einem Falschen Dateinamen die Datei mit den Daten zu öffnen.

    Dazu musst du den Rückgabewert von fopen auswerten, das habe ich jetzt nicht mit aufgeschrieben, irgendwas sollst du ja auch noch selbst machen.

    zweitens scheint die fscanf Funktion so zu funktionieren dass diese keine Daten in die Strucktur schreibt wenn die Platzhalter nicht stimmen.

    Meine Rede. fscanf ist für Anfänger zu kompliziert. Gehe davon aus, dass fscanf fehlerfrei funktioniert und du diese Funktion nur falsch anwendest. Außerdem war mein Vorschlag fgets+sscanf und nicht fscanf, du solltest dich für eine Variante entscheiden und dann jeweils in jedem Fall die Rückgabewerte auswerten!



  • so mein Kram funktioniert jetzt
    ist sicher noch verbesserungsfähig
    Hier mal die gesammte funktion

    int AusDateiLesen(struct Wahren* Artikel, int *anz){
        int i=0,dumpint=0;
        FILE *datei;
        char dumpchar[100];
        char zeile[100];
        strcpy(zeile,"5");   
        datei = fopen ("Datendatei.txt", "r");
        if (datei == NULL){
            printf("Fehler beim oeffnen der Datei.");
            return 1;
        } 
        if (datei != NULL)
        {
            fscanf(datei,"%99s%s%99s%99s%99s",dumpchar,dumpchar,dumpchar,dumpchar,dumpchar);
            //strcpy(dumpchar,"TEST");
            /* Schleife lauft so lange wie Zeilen aus Datei Ausgelesen werden*/
            while (fgets(zeile,100,datei)){            
                /*fscanf liefert die anzahl der Richtig gelesenen Formatspezifizierer an *zeile */
                *zeile==fscanf(datei,"%d %d %99s %99s %lf",&dumpint,&Artikel[i].nr,Artikel[i].bezeichnung,Artikel[i].name,&Artikel[i].preis);
                i++;
            }
            fclose (datei);
        }
        i--;// minus 1 wegen Richtiger Anzahl
        *anz=i;// Zuweisung der Anzahl ausgelesener zeilen in die wichtige Zaelvariable anz,
        return 0;
    }
    


  • So werden die Werte aber nur aus jeder zweiten Zeile genommen.
    Lies es die nochmal genau durch:

    Wutz schrieb:

    Außerdem war mein Vorschlag fgets+sscanf und nicht fscanf,



  • Warum in Zeile 11 kein else?
    Zeile 19 verstehe ich nicht?

    Nur für die Optik - Waren oder Wahren?



  • DirkB schrieb:

    So werden die Werte aber nur aus jeder zweiten Zeile genommen.

    Ich nehme das mit der zweiten Zeile zurück.
    Mit dem fgets liest du nur noch den Rest der Zeile ein, den fscanf übrig gelassen hat. Und wenn es nur das '\n' ist.
    Trotzdem war es so nicht gemeint.



  • Was war so nicht gemeint? das verwirrt mich etwas

    ich bin jedenfalls erst mal zufrieden mit meinem Code, er liefert das was ich haben möchte.
    Obwohl ich selber zugeben muss das mir nicht alles hundert prozentig klar ist was mein Code genau macht.

    Ich versuche das mal zu beschreiben.

    hier lese ich die Zeile mit den Tabellenköpfen ein, diese Zeile wird verworfen.
    Position in der Datei ist jetzt noch Zeile1.

    fscanf(datei,"%99s%s%99s%99s%99s",dumpchar,dumpchar,dumpchar,dumpchar,dumpchar);
    
    while (fgets(zeile,100,datei)){            
                /*fscanf liefert die anzahl der Richtig gelesenen Formatspezifizierer an *zeile */
                *zeile==fscanf(datei,"%d %d %99s %99s %lf",&dumpint,&Artikel[i].nr,Artikel[i].bezeichnung,Artikel[i].name,&Artikel[i].preis);
                i++;
            }
    

    Die Schleife läuft solange wie fgets(zeile,100,datei)einen Wahren wert leifert.
    Wert von zeile ist 5,
    Durch fgets wird nun das Return am Ende von Zeile1 in zeile gespeichert. Position in der Datei ist jetzt Anfang Zeile2
    danach wird fscanf ausgeführt, diese liest mit hilfe der Formatspezifizierer die Zeile aus und weist die gefundenen Zeichenketten dem Strukturarray zu.
    Der Rückgabewert von fscanf sind die Anzahl der richtig ausgelesenen Formatspezifizierer. das sind hier 5.
    i wird erhöt um 1 und wir landen wider bei der Prüfung der Wihle bedingung.
    damit sind wir wieder an der Stelle wo in Zeile2 das Return am Ende Steht.

    Wenn jetzt die letzte Zeile eingelesen wurde liefert fscanf eine 0 an zeile und die Prüfung der while Bedingung ergibt einen Fehler, weil da kein Zeichen mehr kommt. damit wird die Bedingung falsch und die while Schleife wird verlassen.

    Was meint ihr? ist das halbwegs richtig



  • Okay in Zeile 6 kopierst du "5" in zeile.
    In Zeile 17 wird der Inhalt von zeile geändert, oder nicht 😕
    Welche Auswirkung oder Zweck soll der Vergleichsoperator == in Zeile 19 haben?
    Sehe da kein if, while oder ähnliches?



  • RajHid schrieb:

    Was war so nicht gemeint? das verwirrt mich etwas

    Du liest mit Zeile 14 ( fscanf(datei,"%99s%s%99s%99s%99s",dumpchar,dumpchar,dumpchar,dumpchar,dumpchar); ) die Überschriften ein.
    Das '\n' aus der Zeile bleibt aber noch im Eingabepuffer.

    Das wird dann in Zeile 17 ( while (fgets(zeile,100,datei)) ) ausgelesen.
    In Zeile 19 liest du dann die Werte aus der nächsten Zeile (bis auf das '\n').
    Das wird dann in Zeile 17 ...
    Geh mal mit dem Debugger schrittweise durch.

    Gemeint war, die komplette Zeilen mit fgets auslesen und mit sscanf auswerten:

    fgets(zeile,100,datei)  // Überschrift lesen Reichen 100 ZEichen aus?
            /* Schleife lauft so lange wie Zeilen aus Datei Ausgelesen werden*/
            while (fgets(zeile,100,datei)){            
                /*sscanf liefert die Anzahl der richtig gelesenen Formatspezifizierer zurück */
                if (5!=sscanf(zeile,"%d %d %99s %99s %lf",&dumpint,&Artikel[i].nr,Artikel[i].bezeichnung,Artikel[i].name,&Artikel[i].preis)) 
                { Fehler, Was jetzt?
                };
                i++;
            }
    


  • Nen Debugger benutze ich nicht ich mach das nur mit Konsole und vim
    Ist halt manchmal etwas schwieriger.

    Über die Funktion muss ich aber noch mal drüber schauen da sind noch Ungereimtheiten drin.



  • RajHid schrieb:

    Nen Debugger benutze ich nicht ich mach das nur mit Konsole und vim
    Ist halt manchmal etwas schwieriger.

    Fuer den Debugger brauchst du auch nur die Konsole.
    Und der ist auch schon dabei.

    gdb



  • Hab mir mal gdb angeschaut, hätte ich schon eher verwenden sollen hätte mir manches an Zeit erspart. Danke für den Hinweis.


Anmelden zum Antworten