[c++] Problem beim fstream öffnen

radazong

Mitglied

Hallo Community!
Ich habe eine Frage bezüglich eines fstream-Objektes. Undzwar habe ich zwei Funktionen:

1.) Funktion, die aus einer Datei alle Datensätze ausliest, und in einem Vector speichert
2.) Funktion, mit der ich Einträge an diese Datei anfügen kann.

Das Anfügen ansich funktioniert auch einwandfrei. Das Öffnen und Auslesen für sich allein funktioniert auch wunderbar. Nur wenn ich jetzt am Anfang des Programms die 1.) Funktion aufrufe (Open(vector<ENTRY>&) und dann im weiteren Verlauf versuche Datensätze mit der 2.) Funktion (Store(TCHAR*,TCHAR*,TCHAR*)) abzuspeichern funktioniert dies nicht, d.h. ich bekomme bei der Anfrage Datei.good() FALSE zurückgeliefert. Hier erstmal die Funktionsdefinitionen:

C++:
BOOL STOREMANAGER::Store(const TCHAR* name,const TCHAR* money,const TCHAR* date)
{
	ENTRY entr;
	if(!entr.Set(name,money,date))
	return FALSE;
	
	
	Datei.open(File,std::ios::binary|std::ios::app|std::ios::out);
	if(!Datei.good())
	{
	Datei.close();
	return FALSE;
	}

	Datei.write((char*)&entr,sizeof(entr));
	Datei.close();
	return TRUE;
}


BOOL STOREMANAGER::Open(std::vector<ENTRY>& EntrVec)
{
	ENTRY entr;
	Datei.open(File,std::ios::in|std::ios::binary);
	
	if(!Datei.good())
	{
	Datei.close();
	return FALSE;
	}

	while(!Datei.eof())
	{
		Datei.read((char*)&entr,sizeof(entr));

		if(!Datei.eof())
		{
		EntrVec.push_back(entr);
		vEntry.push_back(entr);
		}
	}
	Datei.close();

	/*Datei.seekg(std::ios::beg);
	Datei.seekp(std::ios::beg);*/

	return TRUE;
}

Ich raufe mir hier nun schon seit Stunden die Haare aus und sehe einfach kein Problem.
Ich hoffe, dass mir hier jemand helfen kann, denn ich komme absolut nicht weiter.

Greetz,

RaDazoNG
 
Zuletzt bearbeitet von einem Moderator:
Ich sehe nirgendwo eine Deklaration des fstreams Datei?!
Ich bin mir nicht ganz sicher, ob es erlaubt ist mehrere open-mods zu benutzen, aber zumindes out und app widersprechen sich. Außerdem für deinen fall würde ich ehr einen ofstream benutzen, du willst ja nichts aus der Datei lesen, sondern nur speichern, oder?
 
Hallo!

Das fstream Objekt ist Teil meiner Klasse. Ich schreibe und lese damit. In open(..) lese ich mit dem Objekt und in Store(..) schreibe ich.
Hmm, ich habe bisher immer mit C-Dateioperationen gearbeitet, die stream-Objekte sind mir noch recht fremd, aber wieso widersprechen sich denn ios::out und ios::app? Ich möchte ja die Datei zum schreiben öffnen und das geschriebene am Ende anhängen.

Der Aufruf von Store(..) ohne vorherigen Aufruf von Open(..) funktioniert einwandfrei - das wundert mich ja eben. Andersrum genauso....aber beides zusammen gibt einen Fehler.

Greetz, RadaZOnG
 
Wäre gut, wenn du die Deklaration des fstream-Objekts zeigst..

Übrigens ist es vielleicht sinniger, den fstream als lokale Variable anzulegen, falls er tatsächlich nur so gebraucht wird... (wird er ja in deinen Beispielen)
 
Nunja, ich habe auch eine Store() Funktion für Vectoren implementiert, die auf dieser aufbaut - sprich : Es können durchaus mal 20-50 Aufrufe hintereinander kommen - ist es da nicht unvorteilhaft jedesmal ein lokales Objekt zu erzeugen?
Hier zumindest mal die Deklaration und Initialisierung des Objektes:

C++:
class STOREMANAGER
{
//....
std::fstream Datei;
TCHAR File[155];

public:

//...

};




STOREMANAGER::STOREMANAGER():Datei(),//..
{
lstrcpy(File,TEXT("list.thb"));
}

Hoffe, das hilft dabei mir zu helfen :).


EDIT: Ich habe aus Frust einfach mal lokale fstream Objekte erzeugt - das funktioniert einwandfrei. Das ist jetzt zwar ein zufriedenstellendes Ergebnis, jedoch keine befriedigende Lösung des Problems.
Warum nur liefert das fstream Objekt nach dem ersten öffnen in (STOREMANAGER::Open(..)) bei erneutem öffnen Datei.good()==FALSE?! Es funtkioniert jetzt zwar, über eine erklärende Antwort würde ich mich trotzdem freuen.

Greetz

RaDaZOnG
 
Zuletzt bearbeitet von einem Moderator:
Vielleicht ist in den vorhergehenden Operationen irgendein Fehler passiert oder sonst ein Statuscode gesetzt worden.

Versuche den mal zu clearen mit:

C++:
Datei.clear();

Bevor du Datei.open() aufrufst..
 
Hallo!

Okay, danke - das hat geholfen mit dem clear(). Ich frage mich jedoch, wo zum kukuk ein Fehlerbit gesetzt worden sein könnte.
Vielen Dank jedenfalls für die kompetente Hilfe,

Greetz,

RaDaZOnG
 
So jetzt hab ich mal ne Frage:
Code:
BOOL STOREMANAGER::Open(std::vector<ENTRY>& EntrVec)
{
    ENTRY entr;

    Datei.open(File,std::ios::in|std::ios::binary);
    
    if(!Datei.good())
    {
        Datei.close();
        return FALSE;
        }

    while(!Datei.eof())
    {    
        Datei.read((char*)&entr,sizeof(entr));

        if(!Datei.eof())
        {
            EntrVec.push_back(entr);
            vEntry.push_back(entr);
        }
    }
    Datei.close();

      return TRUE;
}
(1) Warum hast du eine Membervaribale Datei, wenn du diese jedesmal neu öffnest?
(2) Warum nutzt du BOOL und nicht bool? (BOOL == int; sizeof(int) > sizeof(bool)
(3) Schonmal den operator<< überladen? Mach das mal ... macht deinen Code viiel ordentlicher!
(4) Kennst du operator! von std::istream?
(5) Kennst du exception? Wären in diesem Fall angebracht, da einfach es sich um eine Ausnahme handeln sollte, das ein ungültiger Parameter an die Funktion übergeben wird. Ob korrekt eingelesen wurde, überprüfst du ja eh nicht!
(6) C-Style-Cast statt reinterpret_cast? Nicht wirklich gut!
(7) Warum legfst du entr schon so früh an? Wenn die Datei sich nicht öffnen lässt, brauchst du es nicht!


Code:
void StoreManager::open(std::vector<Entry>& vecDestination)
{
    std::ifstream file_stream(m_filename);
    
    if (!file_stream) throw std::invalid_argument("invalid filename");

    Entry tmp;
    while (file_stream >> tmp)
    {    
        vecDestination.push_back(tmp);
        m_data.push_back(tmp);
    }
}
so sehe die Funktion dann aus. Ist doch direkt schön passend. Noch einfacher ghet es dann so:
Code:
void StoreManager::open(std::vector<Entry>& vecDestination)
 {
    std::ifstream file_stream(m_filename);
     if (!file_stream) throw std::invalid_argument("invalid filename");

    std::copy(std::istream_iterator<Entry>(file_stream), std::istream_iterator<Entry>(), std::back_inserter(m_data));
    vecDestination.resize(m_data.size());
    std::copy(m_data.begin(), m_data.end(), vecDestination.begin());
}
... sollte von der Performance her etwas besser sogar sein, da vecDestination nicht mehr vergrößert werden muss (bzw. nur 1mal).

Achja, und zu deinem Problem, dass good == false ist ... achte mal darauf was passiert, wenn man ungekonnt mit eof() umgeht ;) Da liegt unter anderem dein Fehler. eof benutzt man nicht (nur in Ausnahmen) zum einlesen!
 
Hallo!

(1) Weil ich mit dieser Variablen sowohl lese als auch schreibe und ich die bei Bedarf doch öffnen muss, oder nicht?

(2) Weil ich mit der WINAPI arbeite und einfach vorsichtshalber den darin definierten booleschen Wert als Rückgabewert genommen habe.

(3) Gut, das wäre eine Möglichkeit - werde ich mal machen.

(4) Ja, den Operator kenne ich. Habe allerdings gelesen, dass !Datei äquivalent zu !Datei.good() ist, und daher den genommen.

(5) Ja, Exeptions kenn ich - habe ich bis jetzt aber aus einem mir unerfindlichen Grund immer gemieden wie die Pest. Aber wäre ja mal eine Maßnahme sich da reinzulesen.

(6) Ja, 'Schuldig im Sinne der Anklage' -die read-Funktion habe ich irgendwann mal mit c-casts aufgeschnappt, und ich habe es übernommen obwohl ichs eigentlich besser weiss ;) .

(7)Stimmt eigentlich, da gebe ich dir Recht. Das war eben mehr ein grober Entwurf, ohne dass ich mir über soetwas groß Gedanken gemacht habe.


Aber was genau meinst du mit " wenn man ungekonnt mit eof() umgeht "? Naja, ich habe zwar bis jetzt, wie ganz am Anfang beschrieben bisher immer C-Dateioperationen verwendet, und das ist nun mein Debüt zum Thema Streams. Jedoch wüsste ich nicht, wie ich feststellen sollte, wann ich sonst am Ende der Datei angelangt bin.
Ich habe allgemein noch nicht viel mit Containerklassen gearbeitet, und die von dir beschrieben copy-Funktionen verwirren mich auch ehrlichgesagt ein wenig - aber gerteu dem Motto "Try and Error" taste ich mich so langsam in die STL rein.

Vielen Dank für deine Beispiele,

Greetz,

RaDaZOnG
 
(1) Ja, dann brauchst du aber keine Membervariable, wenn du eh immer wieder öffnest und schließt .... Lokal anlegen und den Konstruktor nutzen.
(2) Naja. WinAPI hin oder her. WinAPI ist C, du willst C++ programmieren, also nimm bool. Notfalls erhällst du per !! immer eine BOOL-zu-bool-Konvertierung ;)
(4) Gewöhn es dir an, dass du operator void* bzw. operator! zum Testen da nimmst. Es ermöglicht dir so Sachen wie:
Code:
if (file_stream >> my_variable)
usw.


Mit eof korrekt umzugehen ist so ne Sache. Wann wird das eofbit des Streams gesetzt?

Nungut, die std::copy-Funktion ist so nicht ganz einfach. Dir sind Iteratoren geläufig? Nun die std::copy-Funktion nimmt Begin und End-Iterator der Quelle und Kopiert die in den angegebenen Iterator.
 
Zurück