ifstream/ofstream +array

campinge

Grünschnabel
Hallo gemeinsam!

Ich schlage mich seit einigen stunden mit einem kleinen problem rum.
Ich möchte, dass ein Benutzer meines programmes ein Profil anlegen und speichern kann. Das profil steht hier drin:

Code:
	char *chProfile[] = { "Name", 
						"Farbe", 
						"Setting1",
						"Setting2"
	};

und soll im laufe der arbeiten noch beliebig verlängert werden. Die einzelnen strings sollen dann durch die Einstellungen des Benutzers überschireben werden, sodass ich sie dann mit chProfile[xy] auslesen kann. Das klappt auch prima. Jedenfalls möchte ich dieses Profil jetzt in eine Datei speichern:

Code:
int SaveProfile (char *chProfile[])
{
	char Answer = MessageBox (NULL, "Save your Profile Setup?", "Saving", MB_YESNO);
		
	if ( Answer == IDNO)
		return (0);
	else if (Answer == IDYES)
	{
		ofstream Output ("Profile.pfl", ios::binary);
		for (int i=0; i<sizeof(chProfile)/sizeof(chProfile[0]); i++)
		{
		Output.write ((char*) &chProfile[i], sizeof(chProfile));
		}
		Output.close();
		MessageBox (NULL, "Profile saved", "Saving", 0);
		return(1);
	}
	else 
		return(0);
}
Es wird anscheinend auch gespeichert. Zumindest wird die datei angelegt und es gibt keine Warnungen. Allerdings ist die Datei gerade mal 1kb groß, deshalb glaube ich, dass nicht alles gespeichert wird. Und der gesamte Binary-code sieht in etwa so aus: d‰!
Das kommt mir ein bischen sehr wenig vor...

Dann soll die Datei auch noch ausgelesen werden und dabei das "standardprofil" im programm überschreiben:
Code:
int OpenProfile (char *chProfile[])
{
	ifstream Input ("Profile.pfl", ios::binary);
	if (Input != NULL)
	{
		for (int i=0; i<sizeof(chProfile)/sizeof(chProfile[0]); i++)
		{
		Input.read ((char*) &chProfile, sizeof(chProfile)); 
		} 
		Input.close();
		MessageBox (NULL, chProfile[2], "Profile Loaded", 0);
		return(1);
	}
	else
		return(0);
}
Hier haperts dann, denn die messagebox gibt mir nur das aus, was in dem "Standardprofil steht und nicht das, was ich in die datei speichere.


Ich vermute, dass es irgendwie an dem array liegt, komme aber nicht wirklich klar, da die erklärungen im i-net leider oftmals wenig aufschlussreich sind.

Ich wäre euch sehr dankbar, wenn ihr mir mit ein paar gedankenstößen weiterhelfen könntet!
 
So,
du bekommst hier nen paar Probleme:
(1) Bei übergabe wird Array implizit in Zeiger konvertiert, d.h. du kannst sizeof vergessen (wird dir 4 oder so zurück geben ;) ).
(2) Beim Binary schreiben muss du die länge dazu schreiben, da du sonst ka hast wie viel du wirklich lesen musst.
(3) Wenn du wo rein schreiben willst, muss du entweder per Zeiger oder Referenz arbeiten, wenn es die Funktion überdauern soll ;)
(4) Wie legst du das Array eigtl. an? (also zum einlesen?)

C++:
const bool save_profile(const char** ptr_first, const char** ptr_last)
{
    if (::MessageBoxA(NULL, "Save your Profile Setup?", "Saving", MB_YESNO) == IDNO) return true;
    
    std::ofstream file_stream("Profile.pfl", std::ios_base::binary);
    if (!file_stream) return false;

    for (const char** ptr_it(ptr_first); ptr_it != ptr_last; ++ptr_it)
    {
        const std::size_t length(std::strlen(*ptr_it) + 1);
        file_stream.write(reinterpret_cast<const char*>(&length), sizeof(std::size_t));
        file_stream.write(*ptr_it, length + 1);
    }

    return true;
}
so speicherst du die länge der einzellnen Elemente mit und nebenbei isses so relativ schnell weil de auf unnütze index-operatoren verzichtest ...

C++:
const bool save_profile(const char** ptr_first, const char** ptr_last)
{
    std::ifstream file_stream("Profile.pfl", std::ios_base::binary);
    if (!file_stream) return false;

    for (const char** ptr_it(ptr_first); ptr_it != ptr_last; ++ptr_it)
    {
        const std::size_t length(std::strlen(*ptr_it) + 1);
        file_stream.read(reinterpret_cast<char*>(&length), sizeof(std::size_t));
        *ptr_it = new char[length + 1];
        file_stream.read(*ptr_it, length + 1);
    }

    return true;
}
geht allerdings nur, wenn du weißt wie viele items im profil sind und da du ja auf plain c++ stehst (also ohne std. container) muss du nachher den speicher auch selbst frei geben ...
 
Wow :eek:

Das ist jetzt erstmal harte Kost ;)

Also: Das Array wird in der "Hauptfunktion" aufgerufen und halt an die jeweilige funktion übergeben. Das bleibt also schonmal erhalten.
Aber, dass das so kompliziert wird hätte ich nicht gedach ...

Dabei bleiben jetzt allerdings noch einige fragen über:

1) was übergebe ich jetzt an die Funktion? ich hab ja jetzt 2 const char**. Anscheinend sind das ja jetzt Anfang und ende des arrays, oder?

2) ptr_it ist jetzt mein array?

3) was passiert genau in zeile 11?

Wäre super, wenn du mir die fragen noch beantworten könntest. Ich möchte es ja dann doch verstehen ;D

Kenne leider nur das kleine Beispiel aus dem Buch von Heiko Kalista. Das wird aber nur ein int in eine datei geschrieben und ausgelesn. Und das noch in der Main Funkion ^^
 
Nja eigentlich würde sich hier das einfache Streamen sowieso als schöner darstellen aber okay:
(1)
C++:
const std::size_t size(sizeof(profile) / sizeof(profile[0]));
save_profile(profile, profile + size);
profile entspricht chProfile
(2) ptr_it entspricht in etwa einem Iterator, d.h. auch die abkürzung it. Damit gehst du den Array von Strings durch, d.h. anfangs zeigt ptr_it auf profile[0], dann auf profile[1], usw.
(3) Du castest hier einen Zeiger auf einen std::size_t in einen Zeiger auf char. Der zweite Parameter gibt die Größe des Datenelements an. Ehm ist glaub ich etwas zu viel wenn ich's dir erklären würde, warum jetzt genau auf char* usw ;) const ist es, weil die Daten nicht verändert werden, beim schreiben ...

C++:
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>

const bool save_profile(std::vector<std::string> const& data)
{
    if (::MessageBoxA(NULL, "Save your Profile Setup?", "Saving", MB_YESNO) == IDNO) return true;

    std::ofstream file_stream("Profile.pfl");
    if (!file_stream) return false;

    std::copy(data.begin(), data.end(), std::ostream_iterator<std::string>(file_stream, "\n"));

    return true;
}
so sieht das ganze dann aus, wenn man paar mehr Sachen des Std. Funktion/Klassen-Repertoires nutzt ;)
 
Aha!

Vielen dank für die ausführliche Erklärung. Langsam lichtet es sich jetzt.
Ich werde es im laufe des tages mal einbauen.
Ich Danke dir jetzt schon mal für die Hilfe!!

*EDIT*
so, jetzt hats endglütig funktioniert.
Ich habe mich heute mal im Zug drangesetzt und verstehe auch, was so und wie gemacht wird.

Allerdings musste ich ein paar änderungen durführen, da ich anfangs mit ein paar Fehlermeldungen zugeworfen wurde.
die const char** musste ich alle in char** umwandeln und die for-Schleife:

for (const char** ptr_it(ptr_first); ptr_it != ptr_last; ++ptr_it)

in diese ändern:

for (char** ptr_it=ptr_first; ptr_it != ptr_last; ++ptr_it)

sowie das :

sizeof(std::size_t)

in

sizeof(length)

ändern. Jeztt speichert und lädt er wunderbar durch.
Dank nochmal!
 
Zuletzt bearbeitet:
Zurück