Top-Themen

Aktuelle Themen (A bis Z)

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, 5360 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
Variable aus Datei lesen ohne Datenverlust
gelöst Frage von Frank1993Batch & Shell5 Kommentare

Hallo Leute, ich habe ein Problem beim einlesen einer Variable aus einer Datei. Ich finde keinen Lösungsweg, deswegen wende ...

Microsoft Office
SHS Dateien lesen
Frage von franksigMicrosoft Office3 Kommentare

Hallo zusammen, mal wieder ich mit einem Sonderfall :) Kurze Beschreibung: - Kunde hat alte Office SHS Dateien - ...

VB for Applications
Array aus anderer Datei auslesen
gelöst Frage von jaydotkayVB for Applications2 Kommentare

Hallo liebe Leute, ich würde gerne von einem Makro aus ein Datenfeld auslesen, dass in einer anderen Datei liegt. ...

Windows Userverwaltung
Der Versuch die Datei von einem Domänencontroller zu lesen war nicht erfolgreich
gelöst Frage von SpeedfloWindows Userverwaltung6 Kommentare

Hallo Forumsmitglieder, beim Neustart von Servern, insbesondere nach der Installation von Windowsupdates braucht der AD teilweise bis zu 30 ...

Neue Wissensbeiträge
Erkennung und -Abwehr

Necur-Botnet soll Erpressungstrojaner Scarab massenhaft verbreiten

Information von BassFishFox vor 8 StundenErkennung und -Abwehr

12,5 Millionen Spam-Mails aus einem Bot-Netz mit 6 Millionen Computern? Eigentlich eine schwache Leistung. Die Erpresser setzen dabei auf ...

Microsoft

Nadeldrucker-Problem unter Windows - Microsoft liefert Updates

Information von BassFishFox vor 8 StundenMicrosoft

Hat ja nicht lange gedauert. Nachdem die November-Updates für Windows 7, 8.1 und 10 zahlreiche Nadeldrucker lahmgelegt hatten, stellt ...

Linux

Limux-Ende in München: Wie ein Linux Projekt unter Ausschluss der Öffentlichkeit zerstört wurde

Information von Frank vor 16 StundenLinux14 Kommentare

Mein persönlicher Kommentar zum Thema "Limux-Ende". Die SPD-Politikerin Anne Hübner hat die Richtung von München ganz klar definiert: "Wir ...

Batch & Shell

Open Object Rexx: Eine mittlerweile fast vergessene Skriptsprache aus dem Mainframebereich

Information von Penny.Cilin vor 1 TagBatch & Shell9 Kommentare

Ich kann mich noch sehr gut an diese Skriptsprache erinnern und nutze diese auch heute ab und an noch. ...

Heiß diskutierte Inhalte
Windows Server
Kann man im KMS nachschauen , wieviele Clients den Key in Anspruch genommen haben
gelöst Frage von rainergugusWindows Server15 Kommentare

Hallo, wir haben einen KMS Windows 10 Key. Dieser ist ja W7 kompatibel. Aber unser Windows 7 Pool registriert ...

Linux
Limux-Ende in München: Wie ein Linux Projekt unter Ausschluss der Öffentlichkeit zerstört wurde
Information von FrankLinux14 Kommentare

Mein persönlicher Kommentar zum Thema "Limux-Ende". Die SPD-Politikerin Anne Hübner hat die Richtung von München ganz klar definiert: "Wir ...

Router & Routing
Zwei Netzwerke erstellen
Frage von bunteblumeRouter & Routing14 Kommentare

Hallo Zusammen, Ich möchte gerne ein backup von einem bestimmten Folder welcher auf dem Server regelmässig synchronisiert wird auf ...

Off Topic
Fachkräftemangel in Deutschland? - Talentschmiede schreibt alle 2 Tage die gleichen Stellen aus
Frage von Penny.CilinOff Topic12 Kommentare

Hallo, haben wir in Deutschland Fachkräftemangel? Die Talentschmiede schreibt gefühlt alle zwei Tage dieselben Stellen aus. Und das schon ...