Top-Themen

AppleEntwicklungHardwareInternetLinuxMicrosoftMultimediaNetzwerkeOff TopicSicherheitSonstige SystemeVirtualisierungWeiterbildungZusammenarbeit

Aktuelle Themen

Administrator.de FeedbackApache ServerAppleAssemblerAudioAusbildungAuslandBackupBasicBatch & ShellBenchmarksBibliotheken & ToolkitsBlogsCloud-DiensteClusterCMSCPU, RAM, MainboardsCSSC und C++DatenbankenDatenschutzDebianDigitiales FernsehenDNSDrucker und ScannerDSL, VDSLE-BooksE-BusinessE-MailEntwicklungErkennung und -AbwehrExchange ServerFestplatten, SSD, RaidFirewallFlatratesGoogle AndroidGrafikGrafikkarten & MonitoreGroupwareHardwareHosting & HousingHTMLHumor (lol)Hyper-VIconsIDE & EditorenInformationsdiensteInstallationInstant MessagingInternetInternet DomäneniOSISDN & AnaloganschlüsseiTunesJavaJavaScriptKiXtartKVMLAN, WAN, WirelessLinuxLinux DesktopLinux NetzwerkLinux ToolsLinux UserverwaltungLizenzierungMac OS XMicrosoftMicrosoft OfficeMikroTik RouterOSMonitoringMultimediaMultimedia & ZubehörNetzwerkeNetzwerkgrundlagenNetzwerkmanagementNetzwerkprotokolleNotebook & ZubehörNovell NetwareOff TopicOpenOffice, LibreOfficeOutlook & MailPapierkorbPascal und DelphiPeripheriegerätePerlPHPPythonRechtliche FragenRedHat, CentOS, FedoraRouter & RoutingSambaSAN, NAS, DASSchriftartenSchulung & TrainingSEOServerServer-HardwareSicherheitSicherheits-ToolsSicherheitsgrundlagenSolarisSonstige SystemeSoziale NetzwerkeSpeicherkartenStudentenjobs & PraktikumSuche ProjektpartnerSuseSwitche und HubsTipps & TricksTK-Netze & GeräteUbuntuUMTS, EDGE & GPRSUtilitiesVB for ApplicationsVerschlüsselung & ZertifikateVideo & StreamingViren und TrojanerVirtualisierungVisual StudioVmwareVoice over IPWebbrowserWebentwicklungWeiterbildungWindows 7Windows 8Windows 10Windows InstallationWindows MobileWindows NetzwerkWindows ServerWindows SystemdateienWindows ToolsWindows UpdateWindows UserverwaltungWindows VistaWindows XPXenserverXMLZusammenarbeit

Lesen binärer Dateien in array

Frage Entwicklung C und C++

Mitglied: Bulleye

Bulleye (Level 1) - Jetzt verbinden

11.06.2009, aktualisiert 16:03 Uhr, 5208 Aufrufe, 7 Kommentare

Hallo

Ich bin gerade dabei ein kleines Programm zu schreiben. Dabei muss (für ein 3D-Spiel) ein Array vom Typ folgender Struktur aus einer Datei gelesen werden:

struct Vertex3d 
FLOAT x, y, z; 
DWORD color; 
};
Nun habe ich das einlesen mit verschiedenen Varianten getestet:

fread - liest leider keinen Text ein, obwohl keine Fehler angezeigt werden.
ifstream::get - liest leider nur zeichen ein, aber wandeld diese nicht in ein Float-Wert um

Allerdings, wie man lesen kann , scheint keine Funktion richtig das zu tun, was ich möchte, denn keine Dieser Funktionen liefert einen Wert zurück.

Hat jemand eine Lösung für dieses Problem?

Danke im vorraus.
Mitglied: filippg
11.06.2009 um 16:45 Uhr
Hallo,

fehlt dir vielleicht ein reinterpret_cast?
Mein letztes c++ ist schon wieder ein weilchen her. Aber Serialisierung von komplexen Datenstrukturen geht mit einem ostream (öffnen mit ios::binary|ios::trunc empfehlenswert) ziemlich gut.
Schreiben dann mit
s.write(reinterpret_cast<char *>(&x),sizeof(x));
und einlesen mit
s.read(reinterpret_cast<char *>(&x), sizeof(x));

Gruß

Filipp
Bitte warten ..
Mitglied: Bulleye
11.06.2009 um 17:12 Uhr
Danke erstemal.

Bis hier hin hab ich das verstanden.
Allerdings bekomme ich bei ostream schon beim deklarieren des streams( ostream pFile; ) einen fehler:

'std::basic_ostream<_Elem,_Traits>': Kein geeigneter Standardkonstruktor verfügbar

Demnach kann ich auch nicht testen, ob das mit den reinterpret_cast funktioniert.
Aber was mich schon jetz fragwürdig macht ist, wie ich die eingelesene Zeichenkette(char *) dann in ein float wert, geschweigendenn in einen DWORD wert umwandeln soll.

(Ich verwende MS VisualCpp 2008 falls das ausschlaggebend ist.)
Bitte warten ..
Mitglied: filippg
11.06.2009 um 17:43 Uhr
Hallo,

wenn du nicht postest, wie du deinen stream deklarierst kann man auch schlecht sagen, wo da der Fehler sein könnte.
Aber ich habe einen Fehler bei meinem Post entdeckt: ich verwende oFstream, nicht ostream.
Habe mal ein altes Beispiel ausgekramt.

01.
	void FilterMain::serialize(SimObjekte& so, char* dateiname){ 
02.
		//Datei zur Serilaisierung öffen/anlegen 
03.
		SerializeStream ostream(dateiname, ios::binary|ios::trunc); 
04.
		if(!ostream) 
05.
			throw SchUSi::FileNotFound(string("Die Datei ")+dateiname+" konnte nicht zum Speichern geoeffnet werden."); 
06.
		/** Config::Dateiformatversion: Bei jeder Änderung am Dateiformat sollte diese 
07.
			Konstante auf einen anderen Wert gesetzt werden, Dateien im alten Format 
08.
			(was beim Einlesen Fehler erzeugen würde) können dann nicht mehr 
09.
			geöffnet werden */ 
10.
		ostream.write(reinterpret_cast<char *>(&(Config::Dateiformatversion)),sizeof(Config::Dateiformatversion)); 
11.
		SimObjekt::Realtyp rt; 
12.
		for (unsigned int i = 0; i < so.size(); i++) {				   //iterieren über alle SimObjekte 
13.
			rt = (*so[i]).getRealtyp(); 
14.
			ostream.write(reinterpret_cast<char *>(&rt),sizeof(rt));   //erst speichern, um was für ein Objekt es sich gerade handelt (Realtyp) 
15.
			(*so[i]).serialize(ostream);                               //dann Objekt selber 
16.
17.
		ostream.close();                                               //Serilisierung fertig, Datei schliessen. 
18.
	}
Wobei in einer entsprechenden Header-Datei
typedef std::ofstream SerializeStream;
typedef std::ifstream DeserializeStream;
vorgenommen ist. SimObject: abstrakte Basisklasse der zu serialisierenden Klassen. Realtyp: SimObjekt hat mehrere abgeleitete Klassen. Beim Deserialisieren muss man aber wissen, von welcher konkreten das kommende Objekt ist. Dazu bekommt einfach jedes konkrete Basisklasse eine Int-Konstante zugewiesen, die steht vor den eigentlichen Objektdaten im Stream und zeigt somit, wie die kommenden Daten zu behandeln sind. Dateiformat ist ein int.
Wieder einlesen kann man das ganze dann mit
01.
	void FilterMain::deserialize(SimObjekte& so, const char* dateiname){ 
02.
		//Datei zu Deserialisierung öffnen 
03.
		DeserializeStream istream(dateiname, ios::binary|ios::in); 
04.
		if(!istream) 
05.
			throw SchUSi::FileNotFound(string("Die Datei ")+dateiname+" konnte nicht zur Einlesen geoeffnet werden."); 
06.
		SimObjekt* simO; 
07.
 
08.
		/** Config::Dateiformatversion: Bei jeder Änderung am Dateiformat sollte diese 
09.
			Konstante auf einen anderen Wert gesetzt werden, Dateien im alten Format 
10.
			(was beim Einlesen Fehler erzeugen würde) können dann nicht mehr 
11.
			geöffnet werden */ 
12.
		int DateiformatVersion; 
13.
		istream.read(reinterpret_cast<char *>(&DateiformatVersion), sizeof(DateiformatVersion)); 
14.
		if (DateiformatVersion != Config::Dateiformatversion) { 
15.
        	throw SchUSi::StdError("Die verwendete Datei besitzt das falsche Format, bitte erneut erzeugen.");     
16.
17.
 
18.
		while (istream) {   
19.
// hier wurde dann bis zum Ende des Streams gelesen. Dabei kommt immer erst der oben geschrieben RealTyp, 
20.
// passend zu diesem wird dann ein leeres Objekt dieses Typs erzeugt, dessen Deserialisierungsmethode 
21.
// aufgerufen (istream übergeben). Das Objekt liest dann seine Attributwerte aus dem Stream. 
22.
}
Gruß

Filipp
Bitte warten ..
Mitglied: filippg
11.06.2009 um 18:04 Uhr
Zu reinterpret_cast nochmal: Der ist genau genommen teufelszeug weil er die Verwandlung von Äpfeln in Bananen zulässt ohne auch nur zu wissen, dass beides Obst ist (will heißen: es wird nicht wirklich empfohlen ihn zu verwenden, wo es sich vermeiden lässt).
Aber was mich schon jetz fragwürdig macht ist, wie ich die eingelesene Zeichenkette(char *) dann in ein float wert, geschweigendenn in einen DWORD wert umwandeln soll.
Das ist schon gesehen.
01.
ostream.write(reinterpret_cast<char *>(&(Config::Dateiformatversion)),sizeof(Config::Dateiformatversion)); 
ofstream::write erwartet einen char* und eine Schreiblänge. Dateiformatversion ist ein int. Und mit "reinterpret_cast<char *>(&(Config::Dateiformatversion))" wird ein char* erzeugt, der auf diesen int zeigt. Damit ist ofstream glücklich und klatscht die Daten in den Stream/File (und mit sizeof(Config::Dateiformatversion) gibt man an, wie weit das gehen soll).
Beim Einlesen ist es das gleiche:
ifstream::read ( char* s, streamsize n ); liest n Byte aus dem Stream und schreibt sie an die Stelle, auf die s zeigt.
Da ich weiß, dass im Stream als nächstes "DateiformatVersion" folgt will ich also sizeof(DateiformatVersion) einlesen. Schreiben will ich das eigentlich an DateiformatVersion*, was die read-Methode aber nicht schlucken würde. Also mache ich vorher ein char* draus.

Gruß

Filipp
Bitte warten ..
Mitglied: Bulleye
11.06.2009 um 18:23 Uhr
Sry. die deklaration ist vllt. ein bisschen untergekommen.. deshalb hier nochmal:

01.
ostream pFile;
Ok. Mal angenommen das konvertieren in meine Struktur würde ich diesem Code überlassen:

01.
	// Convert pData to Vertex3d 
02.
	int size = FileStats.st_size / sizeof(Vertex3d); 
03.
	int pos = 0; 
04.
	Vertex3d *tBuffer = (Vertex3d*)malloc(sizeof(Vertex3d)*size); 
05.
	for (int i=0;i<size;i++) { 
06.
	 
07.
		pos = i*3; 
08.
		tBuffer[i].vPosition.x = pData[pos]; 
09.
		tBuffer[i].vPosition.y = pData[pos+1]; 
10.
		tBuffer[i].vPosition.z = pData[pos+2]; 
11.
		tBuffer[i].color = D3DCOLOR_XRGB((int)pData[pos+3],(int)pData[pos+3],(int)pData[pos+3]); 
12.
 
13.
	}
wärend Vertex3d die im Thread-Start stehende Struktur ist, aber ein (wegen der farbe) neues Element hat:

01.
struct Vertex3d 
02.
03.
FLOAT x,y,z;   // Positionen des Vertex 
04.
DWORD color;  // DWORD-EndFarbwert(berechnung über D3DCOLOR_XRGB()) 
05.
INT cred, cgreen, cblue;  // RGB-Farbwerte 
06.
};
Der code ist jetzt für ein Dest-Array gebastelt, das z.B. so aussehen könnte:

01.
[0].vPosition.x = 1.0; [0].vPosition.y = 1.0; [0].vPosition.z = 1.0; 
02.
[0].cred = 100; [0].cgreen = 100; [0].cblue = 100;
Die Datei müsste dementsprechend im Hex-editor so aussehen:

010101646464 ^= ddd

also wäre meine Theorie, jeweils ein Zeichen einzulesen, in Float-zu übersetzen und in die entsprechende Position im pData-Array zu packen.
aber ifstream::get liefert keinen binär eingelesenen Wert, sondern nichts zurück, weil der Text eben binär, und nicht im ASCII format ist.
Oder irre ich mich?

Hat jemand eine Lösung für das einlesen von binären Zeichen und die umwandlung in einen Float wert?
Bitte warten ..
Mitglied: filippg
11.06.2009 um 18:46 Uhr
Hat jemand eine Lösung für das einlesen von binären
Zeichen und die umwandlung in einen Float wert?
Ich dachte, die hätte ich dir das gerade realtiv ausführlich dargelegt. Und im Internet findet man dazu auch noch einiges unter dem Begriff "c++ serialization".
Und wenn du das alles von mir nicht hören willst lass dir wenigstens sagen: ifstream::get ist für deinen Zweck ungeeignet, weil es nur ints zurückgeben kann. Das kannst du der Definition der Methode entnehmen und es steht in jeder C++-Referenz. Verwende stattdessen ifstream::read, das Daten blockweise binär einlesen kann.

Gruß

Filipp
Bitte warten ..
Mitglied: Bulleye
11.06.2009 um 20:27 Uhr
Ok. Wenn ich Daten blockweise einlesen müsste, würde ein block 6 zeichen lang sein.

Wenn ich jetzt einen float-wert Block einlesen würde mit folgender Anweisung...

01.
pFile.read(reinterpret_cast<char *>(&pData), sizeof(pData));
...Dann wäre ja ein Block gleich die ganze Datei, da sizeof(pData) in dem Moment gleich FileStats.st_size, also die größe der Datei ist.
Also müsste ich schreiben

pFile.read(reinterpret_cast<char *>(&pData), sizeof(float)*6);

Demnach müsste ich eine Schleife erstellen, die, die Sprungweite 6 hat und bis zu FileStats.st_size geht.

Sind meine Gedankengänge so richtig?

Lg
Bitte warten ..
Neuester Wissensbeitrag
Windows 10

Powershell 5 BSOD

(8)

Tipp von agowa338 zum Thema Windows 10 ...

Ähnliche Inhalte
Windows Userverwaltung
Dateien mit Admin-Login lesen und kopieren (3)

Frage von istike2 zum Thema Windows Userverwaltung ...

Microsoft Office
SHS Dateien lesen (3)

Frage von franksig zum Thema Microsoft Office ...

Batch & Shell
gelöst Dateien mit vorgegebener Größe erstellbar? (3)

Frage von Stefan007 zum Thema Batch & Shell ...

Windows 7
Kopierte Dateien im Hintergrund anzeigen (1)

Frage von MichiBLNN zum Thema Windows 7 ...

Heiß diskutierte Inhalte
Microsoft
Ordner mit LW-Buchstaben versehen und benennen (21)

Frage von Xaero1982 zum Thema Microsoft ...

Windows Update
Treiberinstallation durch Windows Update läßt sich nicht verhindern (17)

Frage von liquidbase zum Thema Windows Update ...

Windows Tools
gelöst Aussendienst Datensynchronisierung (12)

Frage von lighningcrow zum Thema Windows Tools ...

Windows Server
Suche passender Treiber (12)

Frage von stolli zum Thema Windows Server ...