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, 5327 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 ..
Ähnliche Inhalte
Batch & Shell
Dateien nach Datum verschieben (4)

Frage von LOWTIM zum Thema Batch & Shell ...

Outlook & Mail
Keine RFCs in gesendeten Dateien bei Outlook 2010 (5)

Frage von Laufenfeuer zum Thema Outlook & Mail ...

Neue Wissensbeiträge
RedHat, CentOS, Fedora

Fedora, RedHat, Centos: DNS-Search Domain setzen

(13)

Tipp von Frank zum Thema RedHat, CentOS, Fedora ...

Drucker und Scanner

Samsung SL-M4025ND, firmware update und (kompatible) Tonerkassetten

(1)

Erfahrungsbericht von markus-1969 zum Thema Drucker und Scanner ...

Heiß diskutierte Inhalte
Windows 10
Windows für Privatanwender "nicht mehr handhabbar" (31)

Frage von FA-jka zum Thema Windows 10 ...

LAN, WAN, Wireless
Komplett neues Netzwerk, Ubiquiti WLAN, Router, Switch (15)

Frage von Freak-On-Silicon zum Thema LAN, WAN, Wireless ...

Backup
Backup Wochen- Monats- Jahressicherung (13)

Frage von Meterpeter zum Thema Backup ...

RedHat, CentOS, Fedora
Fedora, RedHat, Centos: DNS-Search Domain setzen (13)

Tipp von Frank zum Thema RedHat, CentOS, Fedora ...