Schnelles Einlesen großer Datenmengen: Welches Dateiformat?



  • Wenn es maximale Performance sein soll, dann ist "nur" ein binäres Format angebracht. Sobald es textuell wird, wird es langsamer. Richtig langsam dürfte wohl sowas wie XML sein.



  • Hallo CStolll,

    würdest du das ganze dann mit einer Textdatei machen? Oder ist das Dateiformat eigentlich egal?



  • CStoll sprach von der verwaltung der Daten im Speicher.. nach dem lesen aus der datei!

    Die frage ist nun ob du die daten erst komplett einliest in den speicher, und dann damit arbeitste was sehr schnell ist..

    Wenn du aber mit den daten direkt aus der datei arbeiten willst, dann "binär" datei verwenden..

    und die nächste frage ist, wie oft du diese "großen" dateimengen in dateien schreiben bzw. lesen willst.. wenn du sie einmal liest, damit im speicehr arbeitest, ist es evtl. irrelevant..vom dateiforamt her



  • VerbalKint schrieb:

    würdest du das ganze dann mit einer Textdatei machen? Oder ist das Dateiformat eigentlich egal?

    Das kommt darauf an 😉
    Wenn du mit den Daten auch außerhalb deines Programms etwas anfangen willst (z.B. dir mit dem Wordpad eine Punktesammlung zusammenschreiben), bleibt nur Textformat.
    Wenn du die Daten nur im Programm verarbeiten willst, dürfte eine Binärdatei geeigneter sein (ein Punkt besteht aus drei int's oder double's und braucht damit binär genau 3*sizeof(koord_type) Byte (in Textform schwankt die Größe zwischen 6 und ca. 30 Byte je nach Inhalt).

    PS: Mein Name hat übrigens nur zwei L 😉



  • Hallo.

    Ich habe eure Hinweise mal verarbeitet und das ist dabei herausgekommen. Ich würde mich sehr freuen, wenn Ihr mir Verbesserungsvorschläge unterbreitet, wie man es effizienter / schneller machen kann, damit ich was dazu lernen kann 😃

    1.Daten in Datei schreiben:

    std::fstream filename;
        filename.open("data.dat",std::ios::out|std::ios::binary);
        if (filename.is_open())
        {
            for (i=0;i<itsAnz;i++)
            {
                itsPkt[i].x = Umkehr(rand()%2)*rand()%grenze;
                itsPkt[i].y = Umkehr(rand()%2)*rand()%grenze/1000.0;
    
                itsPkt[i].z =  itsParam[0] +
                               itsParam[1]*itsPkt[i].x +
                               itsParam[2]*itsPkt[i].y;
    
                filename << itsPkt[i].x << " " << itsPkt[i].y << " " << itsPkt[i].z << "\n"; // '\n' ist hier wahrscheinlich falsch  :confused: 
            }
            filename.close();
        }
    

    2.Daten aus Datei lesen:

    OpenDialog1->FileName = "";
        if (OpenDialog1->Execute())
        {
            filename.open(OpenDialog1->FileName.c_str(),std::ios::in|std::ios::binary);
            if (filename.is_open())
            {
                nr1 = 0;
                     while (getline(filename,zeile))
                     {
                         str.str(zeile);
                         nr2 = 0;
    	          	     while (str >> zahl)
    	          	     {
                             if (!nr2) itsPkt[nr1].x = zahl;
                             if (1 == nr2) itsPkt[nr1].y = zahl;
                             if (2 == nr2) itsPkt[nr1].z = zahl;
                             nr2++;
                         }
                         nr1++;
                }
                filename.close();
            }
            else
                Application->MessageBoxA("Datei konnte nicht geöffnet werden!","Fehler",MB_ICONERROR);
        }
    

    Ich danke für Eure Hilfe.
    V.K.



  • Erstmal: Was genau steckt hinter den ganzen itsIrgendwas-Variablen?

    Zweitens: Die Einlesen-Schleife ist zumindest gefährlich, weil du vorher nicht weißt, wieviele Daten tatsächlich kommen können - das ergibt im Ernstfall einen Speicher-Überlauf (ich hätte mit einem leeren vector<> begonnen und jeweils einen Punkt per push_back() dort reingeschoben).

    Drittens: Das Auseinandernehmen der Eingabezeile ist aber reichlich kompliziert - zumal du immer genau drei Werte hast. Da reicht eigentlich:

    str.str(zeile);
    str>>itsPkt[nr1].x>>itsPkt[nr1].y>>itsPkt[nr1].z;//aber achte auf den verfügbaren Platz
    if(!str) break;
    

    PS: Und auch wenn du die Datei im Binärmodus geöffnet hast - op<< und op>> schreiben in Textform. Zum binären Lesen/Schreiben gibt es read() und write().

    PPS: Hat dir schonmal jemand gesagt, daß man Variablen auch lokal definieren kann 😉



  • VerbalKint schrieb:

    filename << itsPkt[i].x << " " << itsPkt[i].y << " " << itsPkt[i].z << "\n"; // '\n' ist hier wahrscheinlich falsch

    Nein, nicht wahrscheinlich.
    Totsicher.
    MfG
    k.d.d.



  • kenner der dummköpfe schrieb:

    VerbalKint schrieb:

    filename << itsPkt[i].x << " " << itsPkt[i].y << " " << itsPkt[i].z << "\n"; // '\n' ist hier wahrscheinlich falsch

    Nein, nicht wahrscheinlich.
    Totsicher.

    Hör nicht auf ihn, er hat zwar Ahnung von Dummköpfen (vermutlich aus praktischer Erfahrung :D), aber nicht von C++.



  • CStoll schrieb:

    Hör nicht auf ihn, er hat zwar Ahnung von Dummköpfen (vermutlich aus praktischer Erfahrung :D), aber nicht von C++.

    😃

    Warum schreibst du denn den Tinnef da mit rein:

    filename << itsPkt[i].x << " " << itsPkt[i].y << " " << itsPkt[i].z << "\n";

    Ich meine die Leerzeichen und das \n 😕

    Nur mal so ne Anmerkung bezüglich Verbesserungsvorschläge, schneller machen und so.



  • Wenn du die Daten in Textform in die Datei schreibst, brauchst du Trennzeichen, um zu wissen, wo eine Zahl aufhört und wo die nächste beginnt (und auch wenn die Datei als ios::binary geöffnet wurde, schreibt op<< trotzdem in Textform).



  • HI.

    Ich habe das Ganze jetzt modifiziert. Weis aber nicht, ob jetzt alles richtig ist. Könnte es sich bitte jemand anschauen?

    1. Schreiben:

    void __fastcall THauptfenster::Zuflligerzeugen1Click(TObject *Sender)
    {
        //...
        std::stringstream data;
        std::fstream filename;
    
        filename.open("data.bin",std::ios::out|std::ios::binary);
        if (filename.is_open())
        {
            for (i=0;i<itsAnz;i++)
            {
                itsPkt[i].x = Umkehr(rand()%2)*rand()%grenze;
                itsPkt[i].y = Umkehr(rand()%2)*rand()%grenze/1000.0;
    
                itsPkt[i].z =  itsParam[0] +
                               itsParam[1]*itsPkt[i].x +
                               itsParam[2]*itsPkt[i].y;                         
    
                data << itsPkt[i].x << itsPkt[i].y << itsPkt[i].z;
            }
            filename.write(data.str().c_str(),data.str().size());
            filename.close();
        }
    }
    

    2. Lesen:

    void __fastcall THauptfenster::VonDateieinlesen1Click(TObject *Sender)
    {
        int                 i,size;
        char                *data;
        std::fstream        filename;
        std::string	        zeile;
        std::stringstream	str;
    
        OpenDialog1->FileName = "";
        if (OpenDialog1->Execute())
        {
            filename.open(OpenDialog1->FileName.c_str(),std::ios::in|std::ios::binary);
            if (filename.is_open())
            {
                size = filename.tellg();
                data = new char [size];
                filename.read (data,size);
                filename.close();
                itsPkt = new Vektor [size/3];
    
                // Kopiere von data nach itsPkt
    
                delete[] data;
            }
            else
                Application->MessageBoxA("Datei konnte nicht geöffnet werden!","Fehler",MB_ICONERROR);
        }
    }
    


  • Nein, so wird's nichts - mit dem Stringstream schreibst du immer noch Textdaten.

    Bessere Lösung:

    vector<point> mydata;
    
    //schreiben:
    fstream datei(name,ios::out|ios::binary);
    for(i=0;i<mydata.size();++i)
    {
      datei.write(reinterpret_cast<const char*>(&mydata[i]),sizeof(point));
    }
    
    //lesen
    fstream datei(name,ios::in|ios::binary);
    point pt;
    while(datei.read(reinterpret_cast<char*>(&pt),sizeof(point)))
      mydata.push_back(pt);
    


  • VIELEN DANK! So funktionierts jetzt endlich! 👍


Anmelden zum Antworten