große datenmengen in c++ speichern
-
hallo
wir müssen im zuge unserer semiarbeit große Datenmengen (mehrere Millionen Short-Werte) während der laufzeit in c++ auslesen und irgendwo speichern - entweder in arrays (die aber anscheinend nur ca. 120000 elemente vertragen) oder in anderen datenstrukturen, z.b. einer eigenen datei. habt ihr eine idee, wie das von statten gehen könnte (vielleicht mit xml ?!)? oder gibt es keine solche möglichkeit und wir müssen die gesamte datenmenge aufteilen?
-
So spontan fallen mir zwei Möglichkeiten ein:
Entweder du hältst alle Werte im Arbeitsspeicher (auch mit ~600 MB hatte ich bis jetzt nie Probleme, wie kommst du auf 120000?) oder du schreibst alle short-Werte binär in eine Datei, da hast du dann auch random-access. Xml würde ich bei solchen Datenmengen vergessen, erstens ist es sinnlos weil XML quasi nur den Vorteil hat, dass es menschlich lesbar ist, was dir bei > Mio Werten wohl nicht viel bringen sollte, zweitens ist es elend langsam und es gibt Unmengen von potenziellen Fehlerquellen.Achso, hast du, wegen 120000, normale Arrays probiert? Du solltest eher dynamisch Speicher allozieren, also mit new/delete.
-
Wenn du die Daten nach Programmende nicht mehr brauchst, reicht es, sie im RAM unterzubringen - aber da sind die STL-Container vector<> oder deque<> wesentlich flexibler als ein einfaches Array (obwohl, bei den Datenmengen dürfte das fast zu einem Leistungstest für den Heap-Manager werden). Dateien (fstream) brauchst du nur, wenn die Daten das Programmende überleben sollen - oder du es tatsächlich schaffst, die Größenbegrenzung des vector<> zu sprengen.
-
danke für die schnellen antworten!
@badestrand:
ich hab normale arrays genommen, also z.b.: "short Data[120000];". auf die 120000 komme ich, weil etwa bis zu dem wert noch alles gut ging. bei "short Data[150000]" funktionierte es bei gleichem restlichen quellcode nicht mehr. deshalb dachte ich, dass array nur so viele werte vertragen...
in unserer semiarbeit lesen wir wavedateien aus, um die Daten später noch nachzubearbeiten. es wäre also wichtig, dass diese gut ansprechbar sind, z.b. durch indizes wie bei den arrays.
mit speichern im arbeitsspeicher oder in binären dateien hab ich leider keine erfahrung. könntest du mir vielleicht nen link zum nachlesen schicken?
und: sind die daten nicht, wenn man ein array anlegt, auch im arbeitsspeicher oder lässt sich dieser noch direkt ansprechen?@cstoll:
heißt das, dass vectors und deques so etwas wie größere/flexiblere arrays sind?
das wäre ja für die aufgabe ideal, außerdem müssen die daten ja nicht das programmende überleben.
-
Wenn es ums Messwerte aufzeichnen geht, würde ich es in einem Tab-getrennten Spreadsheet speichern.
-
semi schrieb:
in unserer semiarbeit lesen wir wavedateien aus, um die Daten später noch nachzubearbeiten. es wäre also wichtig, dass diese gut ansprechbar sind, z.b. durch indizes wie bei den arrays.
Was machst du denn mit diesen Wave-Dateien genau? Normalerweise stehen die Daten dort schon in einer brauchbaren Form drin (als Binärdatei).
und: sind die daten nicht, wenn man ein array anlegt, auch im arbeitsspeicher oder lässt sich dieser noch direkt ansprechen?
Ja, das Array ist auch im Arbeitsspeicher - aber vermutlich hast du einfach nur die Kapazität des Programmstacks ausgelastet. Wenn du unbedingt mit nackten Arrays arbeiten willst, lagere sie auf den Heap (Zeiger und new[]/delete[] - am besten gekapselt hinter einem STL Container s.u.) oder den Datenblock (static/global) aus, da steht idR mehr Platz zur Verfügung.
@cstoll:
heißt das, dass vectors und deques so etwas wie größere/flexiblere arrays sind?
das wäre ja für die aufgabe ideal, außerdem müssen die daten ja nicht das programmende überleben.Im Prinzip ja - vor allem lässt sich ihre Größe zur Laufzeit anpassen, wenn du das benötigst. Außerdem steht dann auf dem Stack nur eine recht kleine Verwaltungsstruktur, während die Nutzdaten auf dem wesentlich größeren Heap gelagert werden.
(du kannst natürlich auch die Daten gar nicht im Programm speichern, sondern per seekg() durch deine Eingabedatei pflügen)
-
Stefan schrieb:
Wenn es ums Messwerte aufzeichnen geht, würde ich es in einem Tab-getrennten Spreadsheet speichern.
Was bedeutet denn das? Hab ich noch nie gehört, klingt aber interessant
-
ich muss auf die daten wie gesagt leicht zugreifen können. in einer binärdatei oder einer Tab-getrennten datei kann man ja glaub ich nicht einfach den z.b. 1734. datensatz auslesen. ein array wär da immer noch die beste lösung.
ich versuchs jetzt mit der variante:int *Lotto = 0; // Zeiger definieren und sichern Lotto = new int [6]; // Array mit sechs Elementen erzeugen for (i=0; i<6; i++) // Array durchlaufen { Lotto[i] = rand() % 49 + 1; // Lottozahl erzeugen } delete[] Lotto; // Freigabe des Speichers Lotto = 0; // Zeiger sichern
und wenn das nicht geht mit vectors und deques.
gr david
-
semi schrieb:
ich muss auf die daten wie gesagt leicht zugreifen können. in einer binärdatei oder einer Tab-getrennten datei kann man ja glaub ich nicht einfach den z.b. 1734. datensatz auslesen.
Klar kannst du das
Wenn du den 1734ten Datensatz brauchst, setzt du den Dateizeiger einfach auf
1734*sizeof(datensatz)
und liest den Datensatz ein. Geht natürlich nur, wenn die Datensätze eine fixe Länge haben, was bei shorts aber ja der Fall ist. Gerade in wav-Dateien sind die Daten ja schon sequentiell gespeichert, du musst bei der Berechnung des Dateizeigers einfach nur noch den Header überspringen.
Falls sich das mit deinen Anforderungen verträgt, kannst du auch einfach immer nur einen Teil der Daten im Arbeitsspeicher behalten, bei Bedarf einen neuen Block aus der Datei nachholen.
-
Klar kannst du auf das Nte Element zugreifen wenn du weißt wie groß deine Datensätze sind
Und zum Format http://de.wikipedia.org/wiki/CSV_(Dateiformat)
-
Wenn du vorher nicht weißt wie groß deine Daten sind (also falls der Arbeitsspeicher evtl nicht ausreicht), kannst du dir auch eine Verwaltungsklasse dafür schreiben. Wenn genug Platz im RAM ist, kann sie die Daten komplett einlesen, wenn nicht, holt sie die Daten aus der Datei. Oder halt Blockverwaltung. Oder so. Das wäre auch sinnvoll, wenn dein Programm auch auf Rechnern laufen soll, die ein bisschen lau an Arbeitsspeicher sind, wav-Dateien können u.U. ja doch recht groß werden..
-
Badestrand schrieb:
Stefan schrieb:
Wenn es ums Messwerte aufzeichnen geht, würde ich es in einem Tab-getrennten Spreadsheet speichern.
Was bedeutet denn das? Hab ich noch nie gehört, klingt aber interessant
Eigentlich ist es eine Tabelle in Form eines gewöhnlichen Textfiles. Daten in dieser Form lassen sich z.B. sehr einfach als Excel-Tabelle importerieren.
-
semi schrieb:
ich versuchs jetzt mit der variante:
Lass das lieber bleiben und geh gleich zu vector/deque über - ist einfacher zu handhaben und auf die Dauer auch eleganter.
-
wir haben das array jetzt mit der neuen variante groß genug gekriegt. das problem ist jetzt nur noch das auslesen aus der wavedatei, weil wir uns mit zeigern nicht auskennen. wäre es möglich ein beispiel zu posten, wie man eine binäre datei (.wav) gezielt ausliest?
@cstoll:
da das mit dem array geht, lassen wir es erstmal so und versuchen das auslesen der datei hinzukriegen. dann können wir uns auch mit vectors beschäftigen
-
Auslesen kannst du die Daten (am Stück oder in kleineren Abschnitte) mit einem fstream und dessen read() oder readsome() Methode. Wenn du gezielt an einer bestimmten Position anfangen willst, kannst du mit seekg() dorthin springen (da gibtst du den Offset in Byte vom Dateianfang an).
-
Mit was liest du denn die Datei ein? Bei std::ifstream gibts jedenfalls die Methode "read", die liest dir die rohen Daten ein.
-
wir lesen jetzt mit fstream aus der wavedatei aus. doch irgendwie scheint fstream probleme mit dem auslesen von zahlen zu haben...
char ID[4]; char ChunkSize; char Format[4]; char Subchunk1ID[4]; char Subchunk1Size; char AudioFormat; char NumChannels; char SampleRate; char ByteRate; char BlockAlign; char BitsPerSample; char Subchunk2ID[4]; char Subchunk2Size; fstream f("audio.wav", ios::in|ios::binary); //Variablen mit Daten fuellen f.read(&ID[0], sizeof(ID[0])); f.read(&ID[1], sizeof(ID[1])); f.read(&ID[2], sizeof(ID[2])); f.read(&ID[3], sizeof(ID[3])); f.read(&ChunkSize, sizeof(ChunkSize)); f.read(&Format[0], sizeof(Format[0])); f.read(&Format[1], sizeof(Format[1])); f.read(&Format[2], sizeof(Format[2])); f.read(&Format[3], sizeof(Format[3])); f.read(&Subchunk1ID[0], sizeof(Subchunk1ID[0])); f.read(&Subchunk1ID[1], sizeof(Subchunk1ID[1])); f.read(&Subchunk1ID[2], sizeof(Subchunk1ID[2])); f.read(&Subchunk1ID[3], sizeof(Subchunk1ID[3])); f.read(&AudioFormat, sizeof(AudioFormat)); f.read(&NumChannels, sizeof(NumChannels)); f.read(&SampleRate, sizeof(SampleRate)); f.read(&ByteRate, sizeof(ByteRate)); f.read(&BlockAlign, sizeof(BlockAlign)); f.read(&BitsPerSample, sizeof(BitsPerSample)); f.read(&Subchunk2ID[0], sizeof(Subchunk2ID[0])); f.read(&Subchunk2ID[1], sizeof(Subchunk2ID[1])); f.read(&Subchunk2ID[2], sizeof(Subchunk2ID[2])); f.read(&Subchunk2ID[3], sizeof(Subchunk2ID[3])); f.read(&Subchunk2Size, sizeof(Subchunk2Size));
die oben definierten variablen mussten wir alle auf char setzten, weil er sonst "E2034 Konvertierung von 'int *' nach 'char *' nicht möglich in Funktion main() in Zeile 38" ausgab. Doch so werden die Zahlenwerte, wie z.b. ChunkSize nicht korrekt ausgegeben. Buchstabenwerte wie z.b. ID werden dagegen korrekt ausgegeben
-
Du kannst mit read() auch größere Variablen einlesen, mußt sie nur geeignet casten:
int ChunkSize; f.read(reinterpret_cast<char*>(&ChunkSize),sizeof(ChunkSize));
-
ein riesengroßes dankeschön! jetzt gehts und wir können die daten auslesen.
wir machen jetzt feierabend. danke an alle!
-
Und wenn du einen Array hast, kannst du auch einfach den Anfang, wo reingelesen werden soll angeben und dann die Anzahl der Items * die Größe jedes Items als Größe angeben:
file_stream.write(reinterpret_cast<const char*>(&array[start_index]), sizeof(array[0]) * array_size);
... start_index ist meist 0 ...
-
Bei C-Arrays wie der ID geht auch
f.read( ID, sizeof(ID) );