Forum: PC-Programmierung Binärdatei auslesen / reinterpret_cast / C++


von A. R. (redegle)


Lesenswert?

Hallo,

ich würde gerne eine Binärdatei auslesen.
Das ganze soll (muss nicht) mit der Klasse fstream erfolgen. Sollte 
jedoch so effizient wie möglich gestaltet werden.
Die Binärdatei ist wie folgt aufgebaut:

__time64_t, double, double, char,
__time64_t, double, double, char,
...

Später sollen 4 Arrays erstellt werden in denen alle Daten gespeichert 
werden.

Einen einzelnen Wert auslesen klappt wie folgt:
1
__time64_t Zeitstempel = 0;
2
datei.read(reinterpret_cast<char*>(&Zeitstempel), sizeof(Zeitstempel));//Ließt Zeit aus

Die Größe der Binärdatei beläuft sich im Moment auf 52MB. Um nun zu 
vermeiden, dass n Zugriffe auf die Festplatte durchgeführt werden wollte 
ich ersteinmal alle Daten die ich benötige auf einmal in einen String 
schreiben. Das sortieren in Arrays wollte ich dann von diesem String aus 
machen. Siehe Quellcode:
1
Daten = new char[Größe];
2
__time64_t Zeitstempel = 0;
3
datei.read(reinterpret_cast<char*>(&Zeitstempel), sizeof(Zeitstempel));//Ließt Zeit aus
4
datei.read(Daten, Größe);//Kopiert alle Daten in einen String
5
Zeitstempel =  reinterpret_cast<__time64_t>(&Daten[0]);//Ließt Zeit nicht aus

Das Problem ist dass ich die Daten nicht mehr aus dem String gelesen 
bekomme.

Hat jemand eine Idee woran das liegen könnte?

von Peter II (Gast)


Lesenswert?

ich würde es fstream machen - ist mir zu undurchsichtig.
1
while(true) {
2
  __time64_t a;
3
   double b;
4
   double c;
5
   char d;
6
7
   fread( h, &a, sizeof( a ), 1 );
8
   fread( h, &b, sizeof( b ), 1 );
9
   fread( h, &c, sizeof( c ), 1 );
10
   fread( h, &d, sizeof( d ), 1 );
11
12
   //mach was mit a,b,c,d
13
}

fehlerbehandung und abbruchbedingung bitte selber ergänzen.

man könnte auch alles in eine stuct packen, und dann gleichzeig 
einlesen. Das ist ein wenig schneller man muss dan aber wieder 
compilerabhänig mit pragma arbeiten damit die scuct immer gleich ist.

von casud (Gast)


Lesenswert?

Versuch es so:
Zeitstempel = *reinterpret_cast<__time64_t*>(&Daten[0]);

Man beachte die Sterne.

von Peter II (Gast)


Lesenswert?

Peter II schrieb:
> ich würde es fstream machen - ist mir zu undurchsichtig.
ich würde es nicht mit fstream machen - ist mir zu undurchsichtig.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

A. R. schrieb:
> Um nun zu vermeiden, dass n Zugriffe auf
> die Festplatte durchgeführt werden
Völlig falscher Ansatz! Das macht das Betriebsystem schon für dich! 
Nicht optimieren ohne Not... falls es mal wirklich große Daten (im GB 
Bereich) werden kann man das dann noch besser über MemmoryMapped files 
machen, so schießt man sich nämlich nur selbst ins Bein, und schneller 
wird es so auch nicht, da du erst mal die Datei in den Speicher liest 
(welche vermutlich vom BS eh schon gecached wurde) um sie dann nochmal 
zu durchlaufen und so zunächst mal doppelt soviel Speicher anzufordern 
welcher im blödestem Fall auf die HD geswappt werden muss...

von A. R. (redegle)


Lesenswert?

@Peter II,

danke für den Verschlag das werde ich mir später überlegen. Implizit 
bedeutet dein Vorschlag das selbe wie die Aussage von Läubi ...

>Versuch es so:
>Zeitstempel = *reinterpret_cast<__time64_t*>(&Daten[0]);

>Man beachte die Sterne.

OK,
also &Daten[0] liefert mit ein char*
&Daten[0]   -->  char*
reinterpret_cast<__time64_t*>() macht daraus __time64_t*
char*   --> __time64_t*
Das Sternchen vor dem reinterpret cast ließt den Wert an der Position.

Werde das Heute Abend versuchen. Meine aber, dass ich das Gestern auch 
schoneinmal versucht hatte. Macht es ggf. Sinn noch eine Klammer 
einzufügen?

>Zeitstempel = *(reinterpret_cast<__time64_t*>(&Daten[0]));

@Läubi .. ,

danke für die Aussage. Ich meine ich hatte vor ein paar Wochen 
schoneinmal eine ähnliche Diskussion im Forum als ich frage, wie ich 
eine Datei am besten schreiben soll. Wie kann ich mir das beim lesenden 
Zugriff auf die Datei vorstellen? Wird dann zuerst die komplette Datei 
gecached oder ließt das Betriebssystem immer nur einen kleinen Teil aus? 
Wenn ich eine 100MB große Datei öffne macht es keinen Sinn die komplette 
Datei zu lesen. Wenn ich immer nur einzelne Werte auslese macht es auch 
keinen Sinn immer einen Teilbereich zu laden. Woher will das 
Betriebssystem wissen was mein Programm machen möchte. Bzw. welche 
Annahmen trifft das Betriebssystem. Konnte keine Quelle finden wo dies 
erleutert wird.

von Mark B. (markbrandis)


Lesenswert?


von Peter II (Gast)


Lesenswert?

A. R. schrieb:
> Wie kann ich mir das beim lesenden
> Zugriff auf die Datei vorstellen? Wird dann zuerst die komplette Datei
> gecached oder ließt das Betriebssystem immer nur einen kleinen Teil aus?

meist wird einfach der gelesen sektor(oder cluster) gecached. Wenn du 
also 1 byte aus einem sektor(oder cluster ) wird gleich der gesamte 
sektor gelesen und dieser ist dann im cache.

von Karl H. (kbuchegg)


Lesenswert?

A. R. schrieb:

> danke für die Aussage. Ich meine ich hatte vor ein paar Wochen
> schoneinmal eine ähnliche Diskussion im Forum als ich frage, wie ich
> eine Datei am besten schreiben soll. Wie kann ich mir das beim lesenden
> Zugriff auf die Datei vorstellen? Wird dann zuerst die komplette Datei
> gecached oder ließt das Betriebssystem immer nur einen kleinen Teil aus?

Wie das BS das genau macht, ist seine Sache. Aber von einem kannst du 
ausgehen: Das BS liest sicher nicht jedes Byte einzeln von der Platte, 
denn das kann es gar nicht. Platten lassen sich nur Sektorweise lesen 
bzw. schreiben. D.h. das BS holt sich auf jeden Fall mal mindestens 
einen kompletten Sektor in den Speicher aus dem es dann dein Programm 
auf Anforderung füttert.

> Wenn ich eine 100MB große Datei öffne macht es keinen Sinn die komplette
> Datei zu lesen. Wenn ich immer nur einzelne Werte auslese macht es auch
> keinen Sinn immer einen Teilbereich zu laden. Woher will das
> Betriebssystem wissen was mein Programm machen möchte.

Da 98% aller Programme eine Datei einfach von vorne nach hinten lesen, 
ist es nicht ungewöhnlich, wenn man die Annahme trifft: Am Ende eines 
Sektors wird dein Programm höchst wahrscheinlich den darauffolgenden 
Sektor in der Datei lesen wollen. Während also dein Programm einen 
Sektor abarbeitet, kann schon mal der Auftrag an die Platte gehen, den 
nächsten Sektor mal in den Speicher zu schaufeln.

Ob Windows das genau so macht oder nicht, weiß ich nicht. Aber so oder 
so ähnlich wird das laufen.

von A. R. (redegle)


Lesenswert?

Danke für die Hilfe,

muss mir das direkt Verlinken und später in mein privates C/C++ 
Nachschlagwerk eintragen.

Der erste Link zu MSDN war sehr Informativ wusste das so noch gar nicht. 
Die anderen beiden muss ich erst noch komplett verstehen.

Werde das Programm so umschreiben, dass ich alle Daten einzeln lese.

Habe den Fehler nun gefunden.
Wenn ich den Wert von __time64_t auslesen springt der Pointer im Objekt 
weiter und ich muss diesen vorher erst wieder 8Bytes nach vorne Rücken.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.