Problem beim Schreiben in Binärdatei
-
mhhh eigentlich hab ich das schon vorhin ausprobiert, war wahrscheinlich ein Tippfehler drin, den ich nicht gesehn hab.
Funktioniert jetzt alles wunderbar, danke nochmal für die Hilfe

-
Nochmal die Frage. Wozu hier überhaupt ein Zeiger?
Wenn du Zeiger nutzt, reicht am Schluß auch eindelete filestr;Das close() wird dann vom Destruktor automatisch aufgerufen.
-
Naja dynamisch benutz ich es eigentlich in einem anderen Projekt, bei dem es darum geht Bitmaps zu analysieren, bzw zu verändern. Dabei trat halt das Problem auf, dass das mit dem Schreiben nicht klappte, tja jetzt weiß ich ja wiso

Und weil ich den Fehler finden wollte, hab ich halt einen extra Code nur mit der Schreibfunktion geschrieben, um halt das Problem auf einem Blick zu haben und hier nicht lauter Code-Schnipsel rein stellen zu müssen.
-
Nebukat schrieb:
Naja ich find meine jetzige Variante besser, weil ich das Ganze eigentlich in Form von Klassen benutze und das praktische ist, dass ich einfach die Addresse einer kompletten Struktur an die read-Funktion übergeben kann und die Funktion dann einfach eine bestimmte Anzahl von Daten in die einzelnen Variablen der Struktur schreibt, ist z.B. praktisch beim lesen/schreiben von Bitmapfileheader/Bitmapinfoheader.
Vielleicht verstehe ich dich falsch, aber wo wiederspricht das der Verwendung der Streams? Der übliche Weg wäre das man jeweils einen Operator für Eingabe- und Ausgabestreams für die verschiedenen Datentypen anlegt.
cu André
-
Nebukat schrieb:
Naja dynamisch benutz ich es eigentlich in einem anderen Projekt,
Die Frage steht immer noch. Warum?
-
Also wenn ich mal drüber nachdenke gibt es eigentlich keinen zwingenden Grund das fstream-Objekt dynamisch zu erzeugen. Allerdings bin ich gerade dabei mich nach eineinhalbjähriger C++ Abstinenz wieder reinzuarbeiten und beschäftige mich auch zum ersten Mal mit dem Umgang von Dateien.
Ich habs jetzt umgeschrieben, den Zeigerzugriff und die dynamische Erzeugung des fstream-Objekts hab ich entfernt. Sieht jetzt gekürzt so aus:
int main() { BITMAPFILEHEADER BitmapFileheader; BITMAPINFOHEADER BitmapInfoheader; ifstream m_file; m_file.open("Unbenannt.bmp", ios:: in | ios:: binary); if( !inputStream ) { cerr << "Fehler beim oeffnen" << endl; return 1; } // Lesen der FileHeader Informationen m_file.read(reinterpret_cast<char*>(&BitmapFileheader), sizeof(BITMAPFILEHEADER)); ... m_file.close(); system("pause"); return 0; }Außerdem will ich von diesem reinterpret_cast<char*> weg, nur dabei stoße ich wieder auf ein Problem

Mit der read(char* s, streamsize n) Funktion kann man einen Datenblock auslesen, so nun will ich Byte für Byte auslesen, dann muss doch n gleich eins sein und s muss doch dann nur auf einen einfachen char zeigen und wenn der ausgelesene Inhalt dann in einer integer Variablen gespeichert werden soll, brauch ich doch nur schreiben "x = int(*buffer);"; nur irgendwie funktioniert es nicht so, hier noch mal der Code dazu:int x = 0; char* buffer = new char; for(int i=0; i<10; i++) { m_file.read(buffer, 1); x = int(*buffer); cout<<"Inhalt von buffer: "<< x<< endl; } delete[] buffer;
-
Wenn du nur ein char lesen willst, nimm lieber get.
int x = 0; char ch; for(int i=0; i<10; i++) { m_file.get(ch); x = int(ch); cout<<"Inhalt von buffer: "<< x<< endl; }Das byteweise Einlesen ist aber viel langsamer als das Einlesen ganzer Blöcke mit read oder readsome.
-
Nebukat schrieb:
Außerdem will ich von diesem reinterpret_cast<char*> weg, nur dabei stoße ich wieder auf ein Problem

dann wäre es eine Möglichkeit sich seinen eigenen Binärstream zu basteln. Das geht mittels Ableiten von std::basic_ios<>. Etwa
class ibinstream : public std::basic_ios< char > { public: typedef std::basic_ios< char > base_type; explicit ibinstream( std::streambuf* sb = 0 ) : base_type( sb ) {} ibinstream& operator>>( WORD& x_ ) { if( good() ) { WORD x; if( rdbuf()->sgetn( reinterpret_cast< char* >( &x ), sizeof(WORD) ) == sizeof(WORD) ) x_ = x; else setstate( std::ios_base::failbit | std::ios_base::eofbit ); } return *this; } ibinstream& operator>>( DWORD& x_ ) { if( good() ) { DWORD x; if( rdbuf()->sgetn( reinterpret_cast< char* >( &x ), sizeof(DWORD) ) == sizeof(DWORD) ) x_ = x; else setstate( std::ios_base::failbit | std::ios_base::eofbit ); } return *this; } };Das wäre die Minimalausstattung zum Lesen von WORD und DWORD.
Auf der Basis baue man sich eine Funktion, die z.B. die BITMAPFILEHEADER-Struktur liest.
// -- BITMAPFILEHEADER ibinstream& operator>>( ibinstream& in, BITMAPFILEHEADER& hdr ) { const WORD bmp_type = 0x4D42; // 0x4D42 in memory: 0x42 0x4D means "BM" if( in >> hdr.bfType ) { if( hdr.bfType != bmp_type ) in.setstate( std::ios_base::failbit ); else { in >> hdr.bfSize >> hdr.bfReserved1 >> hdr.bfReserved2 >> hdr.bfOffBits; } } return in; }Das Einlesen der einzelnen Member statt der gesamten Struktur garantiert, dass es keine Probleme beim packing gibt.
Die Anwendung ist dann relativ straight forward:
int main() { using namespace std; ifstream file( "Unbenannt.bmp", ios_base::binary ); if( !file.is_open() ) { cerr << "Fehler beim oeffnen" << endl; return 1; } ibinstream in( file.rdbuf() ); // Binärstream verwenden BITMAPFILEHEADER hdr; if( in >> hdr ) { cout << "Header gelesen" << endl; } return 0; }Gruß
WernerPS.: benötigte includes
#include <iostream> #include <fstream> #include <windows.h> // WORD, DWORD, BITMAPFILEHEADER
-
Moin,
erstmal danke für die Antworten, die Idee mit der Erstellung eines eigenen Binärstreams ist ziemlich interessant und ich werd mir in den nächsten Tagen mal das näher zur Gemühte führen

Allerdings hab ich zu erst noch zwei andere Fragen. Zum einen zur get()-Funktion, die hab ich jetzt implementiert, aber bei der Ausgabe steht zehn mal eine -1, aber eigentlich sollte da zehn mal eine 255 stehn. Hier mal der zugehörige Code:
// lesen eines Bytes mit get-Funktion int x = 0; char buffer; for(int i=0; i<10; i++) { m_file.get(buffer); x = int(buffer); cout<<"Inhalt von buffer: "<< x<< endl; }Ich hab auch noch mal in einer C++ Referenz nachgeschaut und dort stand die Funktion unter anderem so drin:
istream& get ( char& c ); - Extracts a character from the stream and stores it in c.
und eigentlich nutz ich diese ja auch so und ich verstehe nicht warum das Programm nur mist ausgibt.
Andererseits funktioniert das Auslesen wiederum, wenn ich die Funktion als "int get();" nutze. Nur würde ich gern verstehen/wissen wo mein Fehler in der obigen Anwendung liegt, weil sonst mach ich ihn vielleicht an einer anderen Stelle wieder.Zum anderen hab ich immer noch ein Problem mit der read-Funktion. Ich will nämlich drei Bytes auslesen, ich weiß nur noch nicht ob ich diese mit der get-Funktion einzeln oder in einem Block per read auslesen werde, denke aber eher als Block, weil es schneller geht.
Zum Problem, es passiert bei der Ausgabe genau das Gleiche wie bei der get-Funktion, es wird statt 255 -1 ausgegeben. Außerdem weiß ich nicht wie ich die drei ausgelesenen char Werte auf einmal oder auch einzeln umwandle und in einen int array speichere. Hier mal der Code, bei dem von den drei ausgelesenen Bytes nur der letzte in einer integer Variablen abgelegt wird:// lesen eines Blockes von 3 Bytes mit read-Funktion int x; char* buffer = new char[3]; for(int i=0; i<1; i++) { m_file.read(buffer, 3); //es werden 3 Werte ausgelesen x = int(*buffer); //wie speichere ich nur einen bestimmten ausgelesenen wert? cout<<"Inhalt von buffer: "<< x<< endl; } delete[] buffer;Oh man hätte nicht gedacht, dass alleine der Ausleseteil so verzwickt wird. Ich muss mich an dieser Stelle schon mal im Voraus für eure Hilfe und beim Lesen dieses langen Beitrags bedanken.
-
Nebukat schrieb:
Allerdings hab ich zu erst noch zwei andere Fragen. Zum einen zur get()-Funktion, die hab ich jetzt implementiert, aber bei der Ausgabe steht zehn mal eine -1, aber eigentlich sollte da zehn mal eine 255 stehn. Hier mal der zugehörige Code:
// lesen eines Bytes mit get-Funktion int x = 0; char buffer; for(int i=0; i<10; i++) { m_file.get(buffer); x = int(buffer); cout<<"Inhalt von buffer: "<< x<< endl; }Das ist das Problem mit dem signed unsigned mix. Mache einfach
x = int(static_cast< unsigned char >( buffer ));Dein zweites Problem habe ich nicht verstanden. Das Problem ist doch mit dem obigen cast zu lösen - oder ?
Gruß
Werner
-
Was eine falsche Umwandlung alles für Fehler erzeugen kann, unglaublich. Jetzt werden die richtigen Werte ausgegeben.
Dein zweites Problem habe ich nicht verstanden. Das Problem ist doch mit dem obigen cast zu lösen - oder ?
Ja und nein, weil mein zweites Problem bestand aus zwei einzelnen Problemen. Das Problem der falschen Werte ist dank der nun richtigen Typumwandlung behoben. Das zweite Problem war, dass ich nicht wusste wie ich die mit der read-Funktion ausgelesenen drei Werte jeweils in eine Variable speichere, aber mir kam dann doch noch eine Idee und jetzt funktioniert das Auslesen per read-Funktion auch bestens. Die Funktion sieht jetzt so aus:
// lesen eines Blockes von 3 Bytes per read-Funktion int x; char* buffer = new char[3]; for(int i=0; i<6; i++) { m_file.read(buffer, 3); //es werden 3 Werte ausgelesen cout<<"Die drei Farbanteile fuer das "<<i+1<<". Pixel:"<<endl; x = int(static_cast< unsigned char >( *buffer )); // erstes Byte umwandeln cout<<"Blau: "<< x<< endl; ++buffer; //An die zweite Stelle des char array gehn x = int(static_cast< unsigned char >( *buffer )); // zweites Byte umwandeln cout<<"Guen: "<< x<< endl; ++buffer; //An die dritte Stelle des char array gehn x = int(static_cast< unsigned char >( *buffer )); // drittes Byte umwandeln cout<<"Rot: "<< x<< endl<< endl; } delete[] buffer;Noch mal danke an alle die mir geholfen haben

-
oder so
for(int i=0; i<6; i++) { m_file.read(buffer, 3); //es werden 3 Werte ausgelesen cout<<"Die drei Farbanteile fuer das "<<i+1<<". Pixel:"<<endl; x = int(static_cast< unsigned char >( buffer[0] )); // erstes Byte umwandeln cout<<"Blau: "<< x<< endl; x = int(static_cast< unsigned char >( buffer[1] )); // zweites Byte umwandeln cout<<"Guen: "<< x<< endl; x = int(static_cast< unsigned char >( buffer[2] )); // drittes Byte umwandeln cout<<"Rot: "<< x<< endl<< endl; }
-
Moin,
beim erweitern des Programms haben sich mal wieder zwei neue Fragen ergeben und zwar weiß ich nicht wie ich bei der write-Funktion alle Elemente eines array/vector auf einmal übergeben kann, gibt es dafür vielleicht spezielle Befehle

// Bild erstellen char pixel_zeile [600]; srand((unsigned)time(NULL)); for(int j=0;j<200;j++) { for(int i=0;i<600;i++) { pixel_zeile [i] = char(static_cast< unsigned char >( rand()%256 )); } crypt_file.write( , 600); //Wie übergibt man alle Elemente eines arrays auf einmal??? }// Bild erstellen vector<char> pixel_zeile; srand((unsigned) time(NULL)); for(int j=0;j<200;j++) { for(int i=0;i<600;i++) { pixel_zeile.push_back(char(static_cast< unsigned char >( rand()%256 ))); } crypt_file.write( , 600); //Wie übergibt man alle Elemente eines vectors auf einmal??? crypt_file.clear(); }
-
Ah mir is doch noch eine Möglichkeit eingefallen.
char* buffer = new char[600]; srand((unsigned)time(NULL)); for(int j=0;j<200;j++) { for(int i=0;i<600;i++) { buffer [i] = char(static_cast< unsigned char >( rand()%256 )); } crypt_file.write(buffer, 600); } delete[] buffer;Würde mich aber über weiter Vorschläge freuen.