Automatisches Schließen mit ofstream?
-
Hallo,
ich komme einfach nicht mehr weiter. Ich habe mir eine Klasse geschrieben, welche mit I/O-Aufgaben vereinfachen soll.
Insbesondere hat diese Klasse einen Zeiger auf ein ofstream Objekt. Im Konstruktor, welchen ich einen Dateinamen übergebe, wird dieses stream Objekt initialisiert und geöffnet. Innerhalb des Konstruktors ist alles gut (ich kann sogar Testausgaben fahren). Sobald ich aber da herauskomme, wird der stream geschlossen. o_O Das verwirrt mich doch sehrZur Verdeutlichung:
Konstruktor:
IOWriter::IOWriter(char* const fName) { stream = new std::ofstream(fName, std::ios::out | std::ios::binary); opened = true; // Test sachen if (stream == NULL) std::cout << "Error " << std::endl; else if (!(stream->is_open())) std::cout << "Error, not open " << std::endl; else std::cout << "Stream opened " << std::endl; *stream << 1 << 2; // dies wird ohne probleme geschrieben }Mein Aufrufprogramm:
IOWriter iow("C:\\test.bin""); iow.isOpen();Wobei
IOWriter::isOpen() { if (stream->is_open()) std::cout << "is open" << std::endl; else std::cout << "not open" << std::endl; }mir immer not open liefert.
Somit kann ich natürlich nicht mehr einfach weitergehend schreiben. Weiss jemand Rat? Ist das beabsichtigt? Übersehe ich irgendetwas?Vielen Dank im Voraus für jegliche hilfreiche Hinweise.
Mat
-
Kleiner Hinweis: Der Vergleich "stream == NULL" ist unnnötig, da der Fall "stream == NULL" nie auftreten kann. Wenn 'new' nicht funktioniert, wird ansonsten ein Fehler geworfen, es sei denn, du verwendest explizit den parameter 'std::nothrow' beim Aufruf von 'new'.
Der Rest sollte eigentlich funktionieren.
-
Ja,
sollte eigentlich =(.
Ich werde einfach noch mal per Hand von Neuen entwerfen, vielleicht finde ich irgendwo einen Haken. Danke soweit.
-
Kleine Randfrage: Warum legst du den Stream überhaupt auf dem Heap ab? So groß sind die Streams nicht, da kannst du sie auch direkt in deine Klasse einfügen.
Ansonsten schließt sich ein Stream eigentlich nur, wenn du es ihm sagst.
-
Es ging mir darum, dass ich schon vorher in dem Stream gelesen/geschrieben habe und bzw. von anderer Stelle aus.
Im Moment habe ich es hinbekommen, dass er sich nicht schliesst. Allerdings habe ich immer noch ein Problem beim [edit] Lesen [/edit]:
*stream >> buf;Setzt den Dateizeiger nicht weiter, falls ich diesen Code mehrfach hintereinander ausführe, lese ich ein und dasselbe Byte eben auch mehrfach. Erst:
*stream >> buf; stream->seekg(1);verschafft diesem Abhilfe. Ist das so richtig?
Danke für die Hilfe soweit,
Mat.
-
Mit >> schreibst du überhaupt nicht, sondern liest Daten aus dem Stream ein. Und eigentlich sollte das auch den Lesezeiger weiterschieben. Probleme könntest du höchstens bekommen, wenn du den selben Stream sowohl zum Lesen als auch zum Schreiben verwendest (bei den C-Funktionen mußt du das File zwischendurch neu positionieren, und vermutlich arbeiten die C++ Stream-Methoden ähnlich).
-
Ja, war ein Schreibfehler, meinte natürlich lesen.
Und ja >> sollte eigentlich den Zeiger weiterstellen. Lustigerweise passiert es aber bei mir nicht. Innerhalb meiner Klasse erzeuge ich mitstream = new std::ifstream(); stream->open(fileName, std::ios::in |std::ios::binary);den Stream (in meinem Testfall wird exklusiv nur auf diesen zugegriffen).
Beim entsprechenden Aufruf von readByte (s.o.) wird nun der Lesezeiger leider nicht weitergerückt. Ich dachte vielleicht, dass schon mal jemand so ein Problem hatte. Vielleicht ist ja auch an meinem System was kaputt

-
Zeig doch mal etwas mehr Code. Aus den vorhandenen Fragmenten kann man immer noch nicht sehr viel erkennen. (mein Tip ist ja, daß du auf einen Lesefehler (oder EOF) gestoßen bist und deshalb nicht weiterlesen kannst)
PS: Und nebenbei solltest du mir mal erklären, was das new dort zu suchen hat?
-
Also, dann mach ich mal der Reihe nach:
Meine Klasse sieht im Moment wie folgt aus:
#ifndef BITREADER_H #define BITREADER_H #include <fstream> #include <limits> class BitReader { public: BitReader(); BitReader(const char *fileName); BitReader(std::ifstream *stream); unsigned char BitReader::readBit(); unsigned int BitReader::readInt(unsigned short numBits); virtual ~BitReader(void); private: std::ifstream *stream; char buf; unsigned char hbc; short pos; bool opened; void BitReader::readBuffer(); }; #endif // BITREADER_HDer relevante Implementationsteil:
BitReader::BitReader(const char *fileName) { stream = new std::ifstream(); stream->open(fileName, std::ios::in |std::ios::binary); buf = 0x00; pos = 0; opened = true; this->readBuffer(); }Das new ist dazu da, um ein Objekt ifstream im Speicher anzulegen?
Weiter:
void BitReader::readBuffer() { stream->seekg(1); // <-- glitch stream->read(&buf, sizeof(buf)); // *stream >> buf; pos = 0; }(edit)
Ach halt, ich war nicht ganz deutlich:
stream->seekg(1) setzt den immer von der gleichen Position eines weiter, so dass ich mit obiger Variante nicht immer ein Byte weiterlese, sondern immer das 2. Das was man nun machen könnte, einen Zähler einbauen und um diesen dann weiterzuzählen. Aber das sollte ja eigentlich nicht nötig sein, oder?
-
Abgesehen davon, daß in der Klassendeklaration die "BitReader::" Angaben überflüssig ist, sieht das doch recht gut aus (eventuell solltest du das seekg() weglassen, damit schiebst du den Lesezeiger immer wieder zurück auf die selbe Position).
Das new ist dazu da, um ein Objekt ifstream im Speicher anzulegen?
Dann bleibt immer noch die Frage: Warum packst du deinen Stream auf den Heap? Als (direkter) Member der BitReader-Klasse wäre der viel besser aufgehoben.
(PS: Ich weiß vermutlich besser als du, was new macht. Aber ich will von dir wissen, warum du es verwendest ;))
-
Ja, aber wie gesagt, ich wollte der Klasse auch einen Zeiger auf das stream Objekt übergeben. Dann ist wohl auch eine Übergabe per Referenz besser, oder?
Mit dem seek hast du recht, wollte es eigentlich relativ immer um eines verschieben. Lasse ich das seekg weg, liest er halt immer wieder das 1. Byte ein.
(Und ja, du weisst natürlich besser, was ein new zu bedeuten hat. Aber du hast ja gefragt

(edit)
Nun weiss ich, warum ich es mit Zeigern gelöst hatte...
Da stream als privat deklariert ist, kann ich keine Referenz darauf übergeben (?).error C2249: 'std::basic_ios<_Elem,_Traits>::operator =' : no accessible path to private member declared in virtual base 'std::basic_ios<_Elem,_Traits>'
bzw:
D:\Programme\Microsoft Visual Studio 8\VC\include\fstream(548) : error C2248: 'std::basic_streambuf<_Elem,_Traits>::operator =' : cannot access private member declared in class 'std::basic_streambuf<_Elem,_Traits>'
with
[
_Elem=char,
_Traits=std::char_traits<char>
]
D:\Programme\Microsoft Visual Studio 8\VC\include\streambuf(23) : see declaration of 'std::basic_streambuf<_Elem,_Traits>::operator ='
with
[
_Elem=char,
_Traits=std::char_traits<char>
]
This diagnostic occurred in the compiler generated function 'std::basic_filebuf<_Elem,_Traits> &std::basic_filebuf<_Elem,_Traits>::operator =(const std::basic_filebuf<_Elem,_Traits> &)'
with
[
_Elem=char,
_Traits=std::char_traits<char>
]
-
Da ist es am besten, den Stream direkt in dein Objekt reinzupacken:
class BitReader { public: ... private: std::ifstream stream;//Achtung: hier kein * ... }; BitReader::BitReader(const char* fname) { stream.open(fname,std::ios::in | std::ios::binary); ... } void BitReader::readBuffer() { //Debug-Ausgabe: clog<<stream.tellg()<<endl; stream.get(buf); pos=0; }Edit: Und afaik gibt es einen guten Grund, einen Stream nicht kopieren zu müssen. Das bedeutet allerdings für dich, daß dein BitReader auch nicht kopierbar sein wird.
-
Habe die Änderungen eingepflegt und nun funktioniert es.
(Sollte es aber auch nicht im anderen Falle funktionieren?)
Vielen Dank für deine Hilfe.
ps Gibt es einen relevanten Unterschied, was man benutzen sollte:
stream >> buf; // oder stream.read(&buf, 1); // oder stream.get(buf);
-
Ja, es gibt marginale Unterschiede in der Bedeutung:
- op>> liest strukturiert (das heißt, er interpretiert die eingabedaten je nach Zielvariable - und er sortiert Whitespaces aus)
- get() liest zeilenorientiert (für ein einzelnes Zeichen macht das keinen Unterschied - aber bei größeren Blöcken bedeutet es, daß er am ersten \n anhält)
- read() liest blockorientiert
(und um ein einzelnes Zeichen einzulesen, ist get() imho am besten geeignet)