Binärdateidefiniton mit Arrays -> einlesen in std::vector ?
-
Okay, angenommen ich habe eine Definition einer Binärdatei, die so aussieht:
// Dateiaufbau struct Vertices { int vertexAnzahl; Vertex vertices[vertexAnzahl]; }; // Das dazugehörige struct: struct Vertex { float x; float y; float z; };
Ich habe dazu folgende Fragen:
- Ich kann zuerst die vertexAnzahl einlesen, und dann nach und nach die einzelnen vertices in einen std::vector pushen. Die folgende Lösung funktioniert, ist aber nicht sonderlich effektiv:
std::vector<Vertex> vertices; for(int i=0;i<vertexAnzahl;++i) { Vertex tmpVertex; datei.read (reinterpret_cast<char*>(&tmpVertex),sizeof(Vertex)); vertices.push_back(tmpVertex); }
Kann ich das ohne Schleife machen, so daß ich den std::vector auf einmal fülle? Der Standard garantiert ja, daß Elemente eines vectors hintereinander gespeichert werden. Ich habe folgendes probiert, hat aber nicht funktioniert:
std::vector<Vertex> vertices(vertexAnzahl); datei.read (reinterpret_cast<char*>(&vertices),sizeof(Vertex) * vertexAnzahl);
- Können bei meiner Lösung Probleme hinsichtlich der Endianness entstehen?
- Wie sähe es aus bei mehrdimensionalen Arrays, wäre der Dateikopf so:
// Dateiaufbau mehrdimensionales Array struct Vertices { int vertexAnzahl_1; int vertexAnzahl_2; Vertex vertices[vertexAnzahl_1][vertexAnzahl_2]; };
Ich bin mir sicher daß es eine Möglichkeit gibt, alles auf einmal einzulesen (was natürlich schneller wäre).
Bin für jede Hilfe dankbar
-
cubeman schrieb:
...
// Dateiaufbau struct Vertices { int vertexAnzahl; Vertex vertices[vertexAnzahl]; }; // Das dazugehörige struct: struct Vertex { float x; float y; float z; };
...
Merke: Das Binäre Speicherlayout dieser beiden structs ist nicht festgelegt...
Gruß,
Simon2.
-
Hm, das struct "Vertex" ist natürlich nicht mehr in der Datei gespeichert, das habe ich nur ergänzend geschrieben - war mißverständlich...
Der Dateiaufbau ist also nur:// Dateiaufbau struct Vertices { int vertexAnzahl; Vertex vertices[vertexAnzahl]; };
Die Dateigröße ist somit
sizeof(int) + vertexAnzahl * sizeof(Vertex)
Das Speicherlayout müßte doch dann schon eindeutig sein, oder liege ich da falsch ?
-
cubeman schrieb:
...
Das Speicherlayout müßte doch dann schon eindeutig sein, ...Nein.
cubeman schrieb:
...
...liege ich da falsch ?Ja.
Stichwort: Padding und Alignment.
am Besten versuchst Du nicht, das ganze auf einen Schlag einzulesen, sondern schön elementweise.
Gruß,
Simon2.
-
Danke erstmal für die hilfreichen Antworten!
Die Frage ist nun, wie kann ich überhaupt sicherstellen, daß die Daten korrekt eingelesen werden?
Ich weiß, daß...
- ...die Datentypen der Datei float und int garantiert 32 bittig sind
- ...die Endianness der Datei anscheinend gleich ist wie bei meinem x86 System - Little Endian (da meine gepostete Methode richtige Werte geliefert hat)
Das heißt, auf einem Big Endian System würde schon das erste Element vertexAnzahl falsch eingelesen werden, da die Byte-Reihenfolge anders wäre?
Dies müßte ich dann auch beim elementweisen Einlesen beachten.Alles auf einmal zu lesen wird's somit sowieso nicht spielen
Tja, Datenspeicherung in Textdateien hat schon sein Gutes...
-
cubeman schrieb:
...
Tja, Datenspeicherung in Textdateien hat schon sein Gutes...Eben.
Am Besten liest Du die Datei byteweise ein und interpretierst es entsprechend "Element für element":
// Annahme: Im File steht eine Zahl und dann ein 0-Terminierter String struct A { int i; string s; }; int main() { A a; ifstream in("myfile.dat", ios_base::bin); char inBuf[2]; // Annahme: Du weißt, dass das Integer als 2 Byte BigEndian abgespeichert ist in.read(inBuf, 2); if(in) { // nur, bei Erfolg a.i = inBuf[0]=0x100 + inBuf[1]; } while(in.read(inBuf, 1) && inBuf != '\0') a.s += inBuf[0]; ...
Ist nur ein Minimalbeispiel ... stilistisch würde ich da noch Einiges anders machen und das Ganze evtl. in den operator>>(..., ifstream&) packen.
Gruß,
Simon2.