[C/C++] Alle Daten aus einer Datei einlesen

Dieses Thema im Forum "Programmierung & Entwicklung" wurde erstellt von kalash111, 26. Juni 2011 .

Schlagworte:
Status des Themas:
Es sind keine weiteren Antworten möglich.
  1. 26. Juni 2011
    Alle Daten aus einer Datei einlesen

    Hallo Leute,

    ich habe eine Datei in der sich Daten folgender Struktur befinden. Ich muss jetzt alle Daten der Datei einlesen, weiß aber nicht wie ich das machen soll.Ich kenne eine Lösung mit Hilfe von (!fin.eof()), aber ich krieg das nicht in Zusammenhang mit der Struktur und dem Vector hin. Es geht um folgendes:



    PHP:
    #include <iostream>
    #include <fstream>
    #include <vector>

    using  namespace  std ;

    struct konto
    {
        
    char Personalnr [ 6 ];
        
    char Name [ 21 ];
        
    char Ort [ 21 ];
        
    char Straße [ 21 ];
        
    float Konsotstand ;
    };
    int main ()
    {
        
    vector < konto > liste ;

        
    ifstream fin ( "Konto.dat" );




        return 
    0 ;
    }
    MfG
    kalash111
     
  2. 26. Juni 2011
    AW: Alle Daten aus einer Datei einlesen

    Wo folgte denn die Struktur?
     
  3. 26. Juni 2011
    AW: Alle Daten aus einer Datei einlesen

    Sorry, wenn ich mich unverständlich ausgedrückt habe.
    Es geht um die Aufgabe:

    Bild




    Und mit "folgender Struktur" meinte ich evt. Informationen^^, das was unter "struct" bei meinem Code steht.

    Hoffe jetzt ist es klarer.

    MfG
    kalash111
     
  4. 26. Juni 2011
    AW: Alle Daten aus einer Datei einlesen

    wenn die datei binär gespeichert wurde und alles genauso in der datei liegt wie es in deiner struct beschrieben ist, dann geht das so:

    Code:
    #include <iostream>
    #include <fstream>
    #include <vector>
    
    using namespace std;
    
    struct konto
    {
     char Personalnr[6];
     char Name[21];
     char Ort[21];
     char Strasse[21];
     float Konsotstand;
    };
    
    int main()
    {
     // vektor
     vector<struct konto> liste;
     // der datei-stream
     ifstream fin("Konto.dat", ios::binary);
     // groesse der struktur
     int sk = sizeof(struct konto);
    
     while (!fin.eof()) {
     // temp
     struct konto tmp;
    
     // struktur einlesen aus datei
     fin.read((char *)&tmp, sk);
     // speichern in vektor
     liste.push_back(tmp);
     }
    
     return 0;
    }
    ansonsten musst du deine struct eben stück für stück einlesen.
     
  5. 26. Juni 2011
    AW: Alle Daten aus einer Datei einlesen

    Nein!
    Structs können größer werden, als die Summe ihrer Felder. Das ist sogar häufig so, wegen dem Alignment. Der C/C++ Standard überlässt dies dem Compiler. Genauso ist, wenn ich mich recht erinnere, "float" vom Standard nicht als IEEE754 32bit vorgegeben. Der von Dir beschriebene Code wird vielleicht in 99% aller Fälle funktionieren, trifft aber Annahmen, die nicht allgemeingültig sind.
    Unter Umständen führt der beschriebene Code zu abstürzen oder sonst was.

    Grad nachgezählt: Das struct "braucht" 6+21+21+21+4 = 73 Bytes. Der Compiler wird das höchstwahrscheinlich so nie anlegen.
    Ich gehe mal davon aus, dass sizeof(struct konto) 76 liefern wird (nächste durch vier teilbare Zahl). Darum wirds so schon ärger geben.

    Besser wäre, alle Felder einzeln einzulesen, auf Sinn zu prüfen und in das struct zu schreiben.
     
  6. 26. Juni 2011
    AW: Alle Daten aus einer Datei einlesen

    ohohoh, viel verstanden habe ich nicht vom geposteten^^

    Meinst du für jede Information einen anderen Vector anlegen?
    So habe ich mir das danach gedacht, aber ich dachte, dass es irgendwie auf diese weise möglich ist.
     
  7. 26. Juni 2011
    AW: Alle Daten aus einer Datei einlesen

    Nein, das hat mit dem vector nichts zu tun.

    Zuersteinmal ist die Aufgabenstellung ungenau. Wie soll der reelle Wert "Kontostand" vorliegen? Als ASCII Text? Als IEEE754 Float? Big oder Little Endian?

    Der Rest ist dann im Prinzip recht simpel, das ist jetzt nur zur Orientierung also Copy&Paste wird nicht einfach funktionieren
    PHP:
    // Solange wir Daten lesen können
    while( fin ) {
    konto kto /// neues Konto Objekt anlegen
    // Personal-nummer einlesen, genau 6 bytes:
    fin . read ( kto . Personalnr 6 );
    // Fehler-überprüfung:
    if(! fin ) {
       
    // Fehler! Exception auslösen oder was auch immer
       
    throw  runtime_error ( "read Personalnr failed" );
    }
    // Weiter mit Name, alles genauso:
    fin . read ( kto . Name 21 );
    // wieder Fehlerprüfung:
    if(! fin ) { ... }

    // und so weiter..

    // Beim Float kommt es jetzt drauf an, wie der vorliegt.
    // Das gibt die Aufgabenstellung nicht her.
    // Sagen wir mal, es sind 4 bytes IEEE754 im gleichen
    // Endianess wie das System, auf dem dieser Code ausgeführt
    // wird, dann:
    fin . read (&( kto . Kontostand ),  4 );
    // Fehlerprüfung wieder...

    // So, jetzt ist alles eingelesen, also legen wir das
    // neue Konto-Objekt in den Vektor
    // (Genaugenommen legen wir eine Kopie da rein)
    liste . push_back ( kto );

    // ende while-schleife
    Alles etwas hässlich, aber das ist auch der Aufgabenstellung geschuldet...
     
  8. 26. Juni 2011
    AW: Alle Daten aus einer Datei einlesen

    Doch. Die Struktur kann, falls der Compiler falsche sizeof() Werte zurückgeben sollte, aber auch dementsprechend definiert werden, damit der Compiler nicht rumpfuscht. Das geht per VSC++ mit #pragma pack() und per GCC mit __attribute__ ((packed)).

    Eine solche Struktur kannst Du dann ohne Probleme und mit Sicherheit binär schreiben / lesen. Es sollte aber auch ohne funktionieren, da Du mit Padding auch die gleiche Größe nimmst um die Strukturen abzuspeichern. Solltest Du allerdings auf eine externe Quelle angewiesen sein, musst Du natürlich die Struktur wie oben erwähnt anpassen.

    Betrachtbar hier: C code
    - 14 lines - codepad
     
  9. 26. Juni 2011
    AW: Alle Daten aus einer Datei einlesen

    Weiss ich doch. Ist aber kein Standard-C sondern eine Compiler-Erweiterung, und wie Du schon selber geschrieben hast von Compiler zu Compiler unterschiedlich.
    Warum sollte man jemandem (auch noch einem Anfänger) raten, C-Code zu schreiben, der nur mit manchen Compilern auf manchen Systemen läuft?

    Dazu kommt, dass es selbst wenn man das Packing anpasst, dass Endianess Problem der float variable nicht löst. Selbst wenn man jetzt einfach von IEEE754 ausgehen will...

    EDIT:
    Achso, und das Alignment/Padding geschieht ja nicht ohne Grund. Also entweder nach dem Einlesen Variable für Variable in ein Struct ohne packing, oder mit tw. enormen Performance-Verlusten leben.
    Wenn einem das alles nicht bewusst ist, sollte man lieber die Finger davon lassen
     
  10. 26. Juni 2011
    AW: Alle Daten aus einer Datei einlesen

    Ich bedanke mich sehr für eure Unterstützung, aber irgendwie ist das doch für mich ein wenig kopliziert. Programmieren ist nicht so mein Ding.

    Ich habe nun folgende Lösung gefunden und denke, dass es so passen müsste

    PHP:
    #include <iostream>
    #include <fstream>
    #include <vector>

    using  namespace  std ;

    struct konto
    {
        
    char Personalnr [ 6 ];
        
    char Name [ 21 ];
        
    char Ort [ 21 ];
        
    char Straße [ 21 ];
        
    float Konsotstand ;
    };
    int main ()
    {
        
    int kmax = 0 ;
        
    konto liste ;
        
    vector < konto > Bank ( kmax );
        
        
    ifstream fin ( "C:\\KONTO.DAT" );

        while(!
    fin . eof ())
        {
            
    fin >> liste . Personalnr ;
            
    fin >> liste . Name ;
            
    fin >> liste . Ort ;
            
    fin >> liste . Straße ;
            
    fin >> liste . Konsotstand ;
            
    Bank . push_back ( liste );
            
    kmax ++;
        }

        
    cout << "Sie haben " <<  kmax << "Datensaetze eingelesen" << endl ;

        return 
    0 ;
    }
    Bw sind raus an euch!


    @ Murdoc: Sehe gerade du hattest es ähnlich. Habe den Post aber nicht gesehen, stand dass er gelöscht war!
    MfG
    kalash111
     
  11. 26. Juni 2011
    AW: Alle Daten aus einer Datei einlesen

    ja ich hab den beitrag wieder sichtbar gemacht, da sich failsafe drauf bezog.

    -> thema ist nun wohl erledigt
     
  12. 26. Juni 2011
    AW: Alle Daten aus einer Datei einlesen

    Wir hatten hier auch nie einen Diskussionsrahmen festgelegt, dass wir uns hier nur über ANSI C unterhalten. Ebenfalls wird ein Anfänger auch nicht alle 24h seinen Compiler wechseln, sodass es schwachsinnig wäre ihm nicht die Packing-Variante vorzustellen. Ob er sie annimmt ist eine andere sache.

    Dazu kommt, dass ein Problem wie Du es schilderst nicht ohne weiteres auftritt. Alle gängigen Systeme verwenden Little-Endian.

    Welchen performance Verlust soll es denn geben, oder genauer: wodurch? Es werden x Bytes eingelesen und an Speicherstelle y geschrieben.

    Eine kleine Demonstration:

    Spoiler
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <time.h>
    #include <stdint.h>
    
    #define SIZE (1 << 16)
    
    typedef struct {
     uint32_t a;
     uint8_t b;
    } foo_t;
    
    typedef struct {
     uint32_t a;
     uint8_t b;
    } __attribute__ ((packed)) bar_t;
    
    int main(void) {
     FILE *fd_foo = fopen("foo.dat", "w"),
     *fd_bar = fopen("bar.dat", "w");
     
     time_t t_start, t_diff; 
    
     foo_t foo_tbl[SIZE] = {0};
     bar_t bar_tbl[SIZE] = {0};
    
     uint32_t i;
    
     for(i=0; i<SIZE; i++) {
     foo_tbl[i].a = i*i;
     foo_tbl[i].b = i % 256;
    
     bar_tbl[i].a = i*i;
     bar_tbl[i].b = i % 256;
     }
    
     fwrite(foo_tbl, sizeof(foo_t), SIZE, fd_foo); fclose(fd_foo);
     fwrite(bar_tbl, sizeof(bar_t), SIZE, fd_bar); fclose(fd_bar);
    
     memset(foo_tbl, 0, sizeof(foo_t) * SIZE);
     memset(bar_tbl, 0, sizeof(bar_t) * SIZE);
    
     fd_foo = fopen("foo.dat", "r");
     t_start = time(NULL);
     fread(foo_tbl, sizeof(foo_t), SIZE, fd_foo); 
     t_diff = time(NULL) - t_start;
     fclose(fd_foo);
    
     printf("Reading %u Bytes (Aligned struct): %us\n", (uint32_t)(SIZE*sizeof(foo_t)), (uint32_t)t_diff);
    
     fd_bar = fopen("bar.dat", "r");
     t_start = time(NULL);
     fread(bar_tbl, sizeof(bar_t), SIZE, fd_bar); 
     t_diff = time(NULL) - t_start;
     fclose(fd_bar);
    
     printf("Reading %u Bytes (Packed struct): %us\n", (uint32_t)(SIZE*sizeof(bar_t)), (uint32_t)t_diff);
    
     return 0;
    }

    Selbst bei 65536 Einträgen keinen Unterschied im Sekundenbereich.

    Code:
    Reading 524288 Bytes (Aligned struct): 0s
    Reading 327680 Bytes (Packed struct): 0s
    Etwas angepasst um die Millisekunden-Differenz herauszubekommen:

    Spoiler
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <sys/time.h>
    #include <stdint.h>
    
    #define SIZE (1 << 16)
    
    typedef struct {
     uint32_t a;
     uint8_t b;
    } foo_t;
    
    typedef struct {
     uint32_t a;
     uint8_t b;
    } __attribute__ ((packed)) bar_t;
    
    int main(void) {
     FILE *fd_foo = fopen("foo.dat", "w"),
     *fd_bar = fopen("bar.dat", "w");
     
     struct timeval t_start, t_end;
     double msec = 0.0;
    
     foo_t foo_tbl[SIZE] = {0};
     bar_t bar_tbl[SIZE] = {0};
    
     uint32_t i;
    
     for(i=0; i<SIZE; i++) {
     foo_tbl[i].a = i*i;
     foo_tbl[i].b = i % 256;
    
     bar_tbl[i].a = i*i;
     bar_tbl[i].b = i % 256;
     }
    
     fwrite(foo_tbl, sizeof(foo_t), SIZE, fd_foo); fclose(fd_foo);
     fwrite(bar_tbl, sizeof(bar_t), SIZE, fd_bar); fclose(fd_bar);
    
     memset(foo_tbl, 0, sizeof(foo_t) * SIZE);
     memset(bar_tbl, 0, sizeof(bar_t) * SIZE);
    
     fd_foo = fopen("foo.dat", "r");
     gettimeofday(&t_start, NULL);
     fread(foo_tbl, sizeof(foo_t), SIZE, fd_foo); 
     gettimeofday(&t_end, NULL);
     fclose(fd_foo);
    
     msec = (double)((t_end.tv_sec - t_start.tv_sec) * 1000 + (t_end.tv_usec - t_start.tv_usec) / 1000.0) + 0.5;
     printf("Reading %u Bytes (Aligned struct): %fms\n", (uint32_t)(SIZE*sizeof(foo_t)), msec);
    
     fd_bar = fopen("bar.dat", "r");
     gettimeofday(&t_start, NULL);
     fread(bar_tbl, sizeof(bar_t), SIZE, fd_bar); 
     gettimeofday(&t_end, NULL);
     fclose(fd_bar);
    
     msec = (double)((t_end.tv_sec - t_start.tv_sec) * 1000 + (t_end.tv_usec - t_start.tv_usec) / 1000.0) + 0.5;
     printf("Reading %u Bytes (Packed struct): %fms\n", (uint32_t)(SIZE*sizeof(bar_t)), msec);
    
     return 0;
    }

    Heraus kommt:

    Code:
    Reading 524288 Bytes (Aligned struct): 0.709000ms
    Reading 327680 Bytes (Packed struct): 0.633000ms
    Wir befinden uns also im Mikrosekunden-Bereich.

    Wie man sieht ist die Struktur, die gepackt ist, marginal performanter wird, je mehr Daten transferiert werden. Wo genau soll deiner Meinung nach die Performance leiden?
     
  13. 26. Juni 2011
    AW: Alle Daten aus einer Datei einlesen

    Meinetwegen. Ist aber blöd, wenn er Hausaufgaben unter Linux mit GCC macht und in der Schule mit MVC++ funktioniert es dann nicht. Ich habe eine Lösung vorgestellt, die ohne die Probleme auskommt und sogar auf einem Embedded-System funktioniert (abgesehen von der Float-Variable).
    Was ist der Vorteil von packed structs?

    TCP/IP ist Big Endian. Gut, ist hier egal. PowerPC ist Big Endian, die spielen immernoch eine Rolle. Aber auch das ist egal. Warum soll man Code schreiben, der potentiell inkompatibel ist?

    Durch non-aligned Zugriff. Manche Plattformen haben sich da extrem schwer (wieder PowerPC als Beispiel). Bei x86 macht
    es nur selten einen Unterschied. Bei mehr oder weniger sequentiellem Zugriff kann es tatsächlich sogar schneller sein
    auf Grund der besseren Cache-Lokalität.

    Auch zur Demonstation, folgendes ist bei mir auf Intel x86 im Unaligned (d.h. packed) Fall etwa 4% langsamer, und zwar genau dann wenn durch den gesparten Speicherplatz die Cache-Lokalität nicht erhöht wird, weil sehr "wild" Zugegriffen wird.
    Spoiler
    Code:
    #include <iostream>
    #include <vector>
    #include <boost/timer.hpp>
    
    struct saligned_t {
     int x;
     char y;
    };
    
    struct sunaligned_t {
     int x;
     char y;
    } __attribute__ ((packed));
    
    int main(int argc, char* argv[]) {
     using namespace std;
     srandom( time(NULL) );
     cout << sizeof(saligned_t) << "\n"; ///< 8 bytes
     cout << sizeof(sunaligned_t) << "\n"; ///< 5 bytes
    
     const int SIZE = 1024*1024*10; // 10 MB
    
     // Zufaellig fuellen:
     vector<saligned_t> al;
     vector<sunaligned_t> ul;
     for(int i=0; i<SIZE; ++i) {
     saligned_t a;
     sunaligned_t b;
    
     a.x = b.x = random();
     a.y = b.y = random();
    
     al.push_back(a);
     ul.push_back(b);
     }
    
     boost::timer timer;
     // Random access:
     int sum = 0;
     const int NUM_TRIALS = 1024*1024*100;
     size_t idx = 0;
    
     timer.restart();
     for(int i=0; i<NUM_TRIALS; ++i) {
     /// immer zumindest soviel weiter gehen,
     /// dass wir einen Cache-Miss haben
     idx = (idx + 3*1024 + (random()%1024)) % SIZE;
     sum += al[idx].x;
     }
     cout << "Aligned: " << timer.elapsed() << "\n";
    
    
     idx = 0;
     timer.restart();
     for(int i=0; i<NUM_TRIALS; ++i) {
     idx = (idx + 3*1024 + (random()%1024)) % SIZE;
     sum += ul[idx].x;
     }
     cout << "Unaligned: " << timer.elapsed() << "\n";
    
     // Sicherheitshalber, damit nichts
     // rausoptimiert wird
     volatile int foobar = 1 + sum;
     return foobar==0;
    }
    

    Ist halt wie gesagt alles nicht ohne. Wenn man genau weiss, auf welche Hardware man abzielt kann man soetwas machen. Aber im allgemeinen Fall, erstrecht beim lernen, kann ich persönlich davon nur abraten
     
  14. 27. Juni 2011
    AW: Alle Daten aus einer Datei einlesen

    Deswegen bot ich ihm ja Möglichkeiten für die 2 meistgenutzten Compilern an. Das deine Lösung funktioniert ist gut, aber darauf bin ich ja auch nicht eingegangen.
    Der Vorteil der gepackten, bzw. nicht optimierten Strukuren ist simpel. Es entspricht haargenau der Spezifikation die man gerade verwendet, oder es hilft ganz einfach wie in diesem Beispiel.

    Nunja, ich gehe nicht davon aus das hier TCP/IP eine große Rolle spielt. *g*
    Für eine Hausaufgabe reicht es zu wissen, dass die gängigsten Rechner eben mit Little-Endian arbeiten.

    Interessante Frage. Ziehmlich viel Code auf dieser Welt ist auf anderen Plattformen inkompatibel, dafür aber auf den dafür vorgesehenen effizienter als anderer Code es je sein wird.

    Dem kann man aber auch Abhilfe schaffen, indem man versucht den Ablauf zu optimieren. D.h. u.a. nicht quer im Speicher rumhantieren, das macht ohnehin keinen Sinn.

    Wie auch immer. Wir schweigen so langsam vom Thema ab, aber mir ist eine kleine Diskussion lieber als Dinge unbeachtet und unbesprochen hier stehen zu lassen.

    Sollte noch was zum Thema sagen zu sein, bitte 'ne PN zukommen lassen.
     
  15. Video Script

    Videos zum Themenbereich

    * gefundene Videos auf YouTube, anhand der Überschrift.