fstream - Datei speichern
-
Hallo,
ich habe ein kleines Testprogramm erstellt, aber es funktioniert nicht wie erwartet. Einlesen der Datei funktioniert tadellos - nur beim Speichervorgang scheint irgendwas nicht zu funktionieren. Die Datei verändert sich kein Stück - wenn ich in der ConfigFile::save() Methode die Variable File durch std::cout ersetze erscheinen alle Elemente - auch Elemente aus der Datei - als Ausgabe. Also liegt es wahrscheinlich an File - vielleicht kann mir hier jemand helfen.
Btw:
Ist die Methode wie ich getline benutze überhaupt konform - oder gibt es andere Wege dies zu lösen?Code:
// ConfigFile.cpp #include <iostream> #include <string> #include <sstream> #include <fstream> #include <map> #include "ConfigFile.h" using std::pair; ConfigFile::ConfigFile(const string &Name) : File(Name, fstream::in | fstream::out) { if (!File.is_open()) { return; } string line; while (!File.eof()) { getline(File, line); if (line.empty() || line[0] == '#') continue; stringstream ss (line); string key; string value; getline(ss, key, '='); getline(ss, value); Entrys.insert(pair<const string, string>(key, value)); } } ConfigFile::~ConfigFile() { save(); File.close(); } void ConfigFile::save() { for (auto &it : Entrys) { File << it.first << '=' << it.second << std::endl; } }
// ConfigFile.h #ifndef H_CONFIGFILE #define H_CONFIGFILE using std::string; using std::fstream; using std::map; using std::stringstream; class ConfigFile { public: ConfigFile(const string &Name); ~ConfigFile(); void save(); template <class T> T getValue(const string &key) { const string &item = Entrys[key]; stringstream ss(item); T value; return ss >> value ? value : 0; } template <class T> void setValue(const string &key, T newValue) { stringstream ss; ss << newValue; string item; ss >> item; Entrys[key] = item; } private: fstream File; map<const string, string> Entrys; }; #endif
// main.cpp #include <iostream> #include <string> #include <sstream> #include <fstream> #include <map> #include "ConfigFile.h" int32_t main(int32_t argc, char **argv) { ConfigFile configFile("test.ini"); configFile.setValue<int32_t>("foo", 20); return 0; }
-
was willst du genau machen? Datei einlesen...ja okay und dann?
- den inhalt ausgeben?
- in die datei schreiben?
- einzelne lines ausgeben?kommt leider aus deine Formulierung nicht ganz heraus...
-
Eine Klasse welche eine Datei in eine Map parsen - Format key=value - sowie speichern kann.
-
Du bringst die Datei beim Lesen am Dateiende in einen Fehlerzustand, den du nicht bereinigst. Alle nachfolgenden Operationen schlagen fehl. Bevor du dich jedoch darauf stürzt, mach es gleich sauber: Benutz nicht mehrmals den gleichen Dateizeiger für unterschiedliche Dinge. Mach dir einen ifstream zum Lesen, einen ofstream zum Schreiben. Diese brauchen auch keine Member deiner Klasse zu sein, da du den ifstream nur im Konstruktor brauchst, den ofstream nur bei save.
Noch ein paar Anmerkungen:
- Es ist ja begrüßenswert, dass du die Datei im Destruktor schließt, du hast also nachgedacht, wie man Ressourcen sauber wieder freigibt. Jedoch haben das die Macher vom fstream auch schon gemacht und die Datei wird sowieso schon automatisch geschlossen, wenn dein File-Member zerstört wird.
- Deine Leselogik ist fehlerhaft. Wobei: Nicht ganz: Du hast sie wieder halbwegs richtig gefrickelt, so dass der Fehler nicht auffällt. Was falsch ist: Du prüfst auf Lesefehler, dann liest du, dann verarbeitest du. Das heißt, trotz eines Fehler wird ein fehlerhafter Datensatz verarbeitet und der Fehler fällt erst beim nächsten Schleifendurchgang auf. In C++ liest man nach diesem Muster:while (Leseaktion) { Verarbeitung; }
Wobei ausgenutzt wird, dass der Rückgabewert von Leseaktionen wieder der Stream ist, aus dem gelesen wird, der dann wieder in einem boolschen Kontext ausgewertet werden kann, ob eine vorangegangene Aktion erfolgreich war oder nicht. Konkret bei dir:
while (getline(File, line)) { // Deine Zeilen 23-32 }
-
Funktioniert nun - danke
Gibt es sonst noch Verbesserungsvorschläge?// ConfigFile.cpp #include <iostream> #include <string> #include <sstream> #include <fstream> #include <map> #include "ConfigFile.h" using std::pair; ConfigFile::ConfigFile(const string &Name) : configFile(Name) { ifstream readConfig(configFile); if (!readConfig.is_open()) { return; } string line; while (getline(readConfig, line)) { if (line.empty() || line[0] == '#') continue; stringstream ss (line); string key; string value; getline(ss, key, '='); getline(ss, value); Entrys.insert(pair<const string, string>(key, value)); } readConfig.close(); } ConfigFile::~ConfigFile() { save(); } void ConfigFile::save() { ofstream writeConfig(configFile); for (auto &it : Entrys) { writeConfig << it.first << '=' << it.second << std::endl; } writeConfig.close(); }
// ConfigFile.h #ifndef H_CONFIGFILE #define H_CONFIGFILE using std::string; using std::ifstream; using std::ofstream; using std::map; using std::stringstream; class ConfigFile { public: ConfigFile(const string &Name); ~ConfigFile(); void save(); template <class T> T getValue(const string &key) { const string &item = Entrys[key]; stringstream ss(item); T value; return ss >> value ? value : 0; } template <class T> void setValue(const string &key, T newValue) { stringstream ss; ss << newValue; string item; ss >> item; Entrys[key] = item; } private: const string configFile; map<const string, string> Entrys; }; #endif