Accountinformation aus Textdatei herauslesen
-
ifstream lesen_aus_datei; string dateiname_lesen="test.txt"; lesen_aus_datei.open(dateiname_lesen.c_str(),ios::in);
Redundanz pur. Schreibe einfach
std::ifstream lesen_aus_datei("test.txt"); // Das in-Flag ist überflüssig
char zeichen; while (!lesen_aus_datei.eof()) { lesen_aus_datei.get(zeichen); cout<<zeichen; }
Eine verpönte Weiterlaufbedingung.
char zeichen; while( lesen_aus_datei.get(zeichen) ) cout << zeichen;
Und das
close()
am Ende macht sowieso der Destruktor vonifstream
automatisch. Also überflüssig.Nebenbei - wenn du eine Datei ausgeben willst, schreibe einfach (ungetestet)
std::ifstream stream("Datei.txt"); std::copy( std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>(), std::ostreambuf_iterator<char>(std::cout) );
-
Nun hast du also Zeichen aus einer Datei gelesen und gleich danach wieder ausgegeben. Sind dir irgendwelche Techniken bekannt, mit denen du den Inhalt der Datei hättest speichern können? Lies mal die ganze Datei in eine einzige Datenstruktur. Dann gib sie danach aus.
-
Hallo Simon,
Willkommen im C++-Forum.
Xyriez schrieb:
Nun möchte ich wenn ich als Accountnamen Max Mustermann eingebe,dass er das dazugehörige passwort anfordert und wenn das Passwort richtig ist Die dazugehörige Information preisgibt.
Das erfordert schon relativ viel Wissen über C++, um das zu lösen, und ist als Anfänger-Aufgabe ungeeignet.
Xyriez schrieb:
Nun habe ich aber keine Ahnung wie ich da ran gehen soll das größe Problem scheint mir die datei genau da auszulesen wo ich es haben will
Am besten, Du lädst den gesamten Inhalt der Datei, bearbeitest ihn ggf. und schreibst ihn später am Stück zurück. Wenn Du es nur stückchenweise machen willst, ist eine Datenbank besser geeignet.
Xyriez schrieb:
Ich hab auch schon ein vorgefertigtes Script ist aber glaub zulang ums hier zu posten
.. soviel ist das auch nicht. Anbei ein Programm, welches den ersten Teil Deiner Anforderungen erfüllt. Verstehen wirst Du es wahrscheinlich nicht - erklären will ich es Dir im Vorfeld auch nicht, dazu ist es jetzt schon zu spät am Tag.
#include <iostream> #include <map> #include <string> #include <fstream> struct get_content // ein Helferlein zum Lesen von "keywort: Inhalt" { get_content( const std::string& key, std::string& content ) : key_( &key ) , content_( content ) {} const std::string* key_; std::string& content_; }; std::istream& operator>>( std::istream& in, get_content x ) { std::string key; if( getline( in >> std::ws, key, ':' ) && key != *x.key_ ) in.setstate( std::ios_base::failbit ); return getline( in >> std::ws, x.content_ ); } struct Entry // ein Eintrag in der Datenbank { std::string pw_; std::string info_; }; namespace { const std::string ACCOUNT = "Account"; const std::string PASSWORT = "Passwort"; const std::string INFO = "Information"; } std::istream& operator>>( std::istream& in, Entry& e ) { return in >> get_content( PASSWORT, e.pw_ ) >> get_content( INFO, e.info_ ); } // diese Funktion liest den Inhalt der Datei in die 'map' std::map< std::string, Entry > read_database( const char* filename ) { using namespace std; map< string, Entry > database; ifstream in( filename ); if( !in.is_open() ) { cerr << "Fehler beim Oeffnen von " << filename << endl; return database; } string account; for( Entry e; in >> get_content( ACCOUNT, account ) >> e; ) database[account] = e; if( !in.eof() ) { cerr << "Fehler beim Lesen in " << filename << endl; return map< string, Entry >(); // mit leerem Container zurück } return database; // ok! } // und hier das Hauptprogramm: ruft 'read_database', fragt nach Account und PW und gibt dann die Info aus int main() { using namespace std; map< string, Entry > database = read_database( "input.txt" ); if( database.empty() ) return -2; // da ging was schief cout << "Bitte mit 'x' wie eXit beenden .." << endl; for( string account; cout << ACCOUNT << ": ", getline( cin >> ws, account ) && account != "x"; cout << "\n" ) { auto i = database.find( account ); if( i == end(database) ) { cerr << ACCOUNT << ": " << account << " ist unbekannt" << endl; continue; } Entry& e = i->second; string passwort; cout << PASSWORT << ": "; if( cin >> passwort && passwort == e.pw_ ) { cout << INFO << ": " << e.info_ << endl; } else cerr << "falsches Passwort!" << endl; } return 0; }
Am besten Du stellst konkrete Fragen dazu.
Gruß
Werner
-
#include <iostream> #include <fstream> using namespace std; int main() { ifstream input; // (Objekt wurde noch nicht mit einer Datei assoziiert) //oder //ifstream input("insert_datei_name"); <-- oder gleich assoziieren. input.open("insert_datei_name"); if (input.is_open()) { while(input.good()) { //make file operations //e.g. with getline und anschliessendem String parsen } } else { //Behandlung wenn Datei nicht geoeffnet werden konnte } input.close(); // Falls nachdem arbeiten mit der Datei im selben Scope noch etwas passiert, // was nichts mit der Datei zu tun hat, solltest du die Datei (nach meiner // Meinung) selbst schliessen. Ich persoenlich tue dies immer manuell. return 0;
}
Ich bin ein grosser Fan von http://www.cplusplus.com/reference
Good prueft gleichzeitig 3 "stream flags" die man auch einzeln pruefen kann, eines ist das Ende der Datei.
Quelle: http://www.cplusplus.com/reference/ios/ios/good/
Es gibt mehrere Moeglichkeiten.
1. Du sagst erstmal die Reihenfolge deiner Werte in der Datei sind immer fix und du setzt eine gewisse Syntax voraus.
Dann haettest du so ein Format.
Max Mustermann
1234567
Max Mustermann ist sehr begabt.Mit std::getline(); holst du die Information raus und packst sie in einen String. Du weisst alle 3 getlines gibt es einen neuen User. Du laedst dann d
Der Nachteil ist, wenn ein User kommt und manuell in der Text Datei rumfummelt und die Reihenfolge aendert oder einfach eine Leerzeile pro Nutzer einfuegt stimmt es nicht mehr.
Eine weitere Moeglichkeit waere den String, so wie du ihn jetzt hast, pro Zeile einzulesen und ihn dann zu parsen.
Du solltest es erstmal so rudimentaer wie moeglich halten.
Passwort in Klartext pruefen und erstmal die Nutzer im Speicher halten. (Wie Werner es geschrieben hat).
-
Ruvi, deine Dateileselogik ist falsch. Erst prüfst du (unnötig umständlich mittels good), dann liest du, dann verarbeitest du. Was, wenn beim Lesen ein Fehler auftrat? Dann verarbeitest du ungeprüft Müll. Werner Salomon zeigt schon, wie Leselogik richtig geht, z.B. Zeile 52, 53: Lesen (hier: operator >>), dann verarbeiten (Rückgabewert prüfen), dann Verarbeiten (Zeile 53).
-
SeppJ schrieb:
Ruvi, deine Dateileselogik ist falsch. Erst prüfst du (unnötig umständlich mittels good), dann liest du, dann verarbeitest du. Was, wenn beim Lesen ein Fehler auftrat? Dann verarbeitest du ungeprüft Müll. Werner Salomon zeigt schon, wie Leselogik richtig geht, z.B. Zeile 52, 53: Lesen (hier: operator >>), dann verarbeiten (Rückgabewert prüfen), dann Verarbeiten (Zeile 53).
Danke,(ich lerne noch) wenn ich mich recht erinnere hatte ich dieses "Scheme" aus einem Lehrbuch und habe es seit dem verwendet ohne es hinterher gross in Frage zu stellen.
Ich haette aber noch eine Frage was Werners code angeht.
Nach SeppJ Anmerkung habe ich ihn mehr nochmal richtig angeguckt.Ich habe bis jetzt nur c++ code von mir gesehen und der ist bei weitem nicht so komplex.
Ich bin ehrlich gesagt auch ein wenig geschockt.
Ich habe jetzt an die 30-40min gebraucht um die 90 Zeilen Code von Werner im Detail zu verstehen und nachzuvollziehen.Aber sieht so, die Komplexitaet von c++ code (Schreibstil)in der Realitaet aus und ihr braucht mit den Augen nur einmal rueberfliegen und koennt alles verstehen?
-
Ruvi schrieb:
Danke,(ich lerne noch) wenn ich mich recht erinnere hatte ich dieses "Scheme" aus einem Lehrbuch und habe es seit dem verwendet ohne es hinterher gross in Frage zu stellen.
Ein sicheres Zeichen, dass das Lehrbuch schlecht war.
Zu Werners Code: Der ist schon durchaus eher auf der unverständlicheren Seite ('Tschuldigung Werner, aber das ist einfach so. Das weißt du auch selber). Werner ist einer der wenigen hier im Forum, die sich richtig gut mit den IOStreams auskennen und das sieht man dem Code auch an. Ich kann das recht flüssig lesen, da ich solche Codes selber schon einmal geschrieben habe und daher die typischen Muster kenne. Ich kann mir aber schon vorstellen, dass man, wenn man diesen Stil nicht gewöhnt ist, sehr große Verständnisschwierigkeiten hat.
Im Kern steht da zweimal die typische C++-Leseschleife (aber die richtige, nicht die Version aus deinem Lehrbuch), einmal für die Datenbank:Containertyp container; Elementtyp element; while (eingabestream.lesen(element)) container.einfügen(element);
und einmal für die Nutzereingaben:
Eingabetyp eingabe; while (eingabestream.lesen(eingabe)) verarbeite(eingabe);
Hier mittels einer for-Schleife umgesetzt, um den Gültigkeitsbereich der Variablen klein zu halten.
Wenn man das erkannt hat, dann ist der Rest (insbesondere Zeile 6-40) die Angabe, wie die Leseaktion genau auszusehen hat. Diese ist ein bisschen verschachtelt. In der untersten Ebene stehen ein paar der bekannten, elementaren Operationen (An die Forenklugscheißer: Ja, operator>>(istream &, string&) ist nicht ganz elementar, aber für die Erklärung hier praktisch schon), in Zeilen 18 und 20. Dann kommen mehrere Schichten Logik drumherum, die machen, dass diese einfachen Operationen das hier beschriebene Format korrekt lesen.
-
Aber sieht so, die Komplexitaet von c++ code (Schreibstil)in der Realitaet aus und ihr braucht mit den Augen nur einmal rueberfliegen und koennt alles verstehen?
Ja, genau so ist es. Allerdings ist einmal "überfliegen" etwas übertrieben. Ich zum Beispiel habe etwa zwei Minuten gebraucht, um die Funktionsweise komplett zu verstehen.
Das wird bei dir auch kommen, schließlich ist der Code eigentlich einfach, und du wirst die Elemente viel schneller (wieder)erkennen.Ich bin ein wenig überrascht, dass
read_database
den Dateinamen nimmt, statt eine Referenz aufistream
. Und das die "Fehlerbehandlung" percerr
stattfindet.
Vorschlag:std::map< std::string, Entry > read_database( std::istream& stream ) { using namespace std; map<string, Entry> database; pair<string, Entry> p; while( stream >> get_content(ACCOUNT, p.first) >> p.second ) database.emplace( move(p) ); // Move statt Kopie return database; // Edit¹: Nein, natürlich nicht immer ok. // In database liegen einfach alle Werte, die extrahiert werden konnten, der User muss auf eventuelle Fehler prüfen. }
(ungetestet)
Die komplette Fehlerbehandlung tritt dann in der aufrufenden Funktion auf, die auf EOF testen kann, die Datei öffnet, usw.Edit: SeppJ ist offenbar anderer Meinung. :p
-
Ich korrigiere: Die for-Schleife in der main() ist natürlich ein Meisterwerk von schlecht lesbarem Code. Werner macht solche Schleifen dauernd.
Aber sonst ist das doch eigentlich ganz gewöhnlicher Code.
-
Erstma danke für die vielen Antworten^^
aber leider kann ich mit einigen sachen im Moment noch nix anfangen
Ich denk ich werd einfach in 1-2 wochen nochmal hierdrauf zurückgreifen
-
Hallo Ruvi,
Ruvi schrieb:
Ich habe bis jetzt nur c++ code von mir gesehen und der ist bei weitem nicht so komplex.
Ich bin ehrlich gesagt auch ein wenig geschockt.
Ich habe jetzt an die 30-40min gebraucht um die 90 Zeilen Code von Werner im Detail zu verstehen und nachzuvollziehen.Aber sieht so, die Komplexitaet von c++ code (Schreibstil)in der Realitaet aus und ihr braucht mit den Augen nur einmal rueberfliegen und koennt alles verstehen?
bedenke bitte, ich das seit Jahren (Jahrzehnten) beruflich mache, und Du - so vermute ich - noch relativ am Anfang stehst. Es erwartet auch niemand von einem Tischler-Lehrling im ersten oder zweiten Lehrjahr, dass er eine geschwungene Holztreppe inklusive Geländer entwerfen und bauen kann.
Von daher brauchst Du nicht geschockt zu sein, das ist ganz normal. Und es freut mich, dass Du den Code immerhin verstanden hast. Das Muster ist immer das gleiche. Struktur anlegen, um eine Datenelement unterzubringen (hier
Entry
, bzw.std::pair<string,Entry>
), Extraktor dazu schreiben (operator>>
), passenden Container wählen (hierstd::map
) und dann Lesen-Prüfen-und-rein in den Container. Etwas Rahmenwerk drumherum und ggf. ein Helferlein (hierget_content
), um Redundanzen abzufangen und - ja und, um den Code lesbarer zu gestalten. Letzteres setzt natürlich voraus, dass man die Mechanismen dahinter kennt.@SeppJ, @Arcoth: Ihr habt natürlich recht - ich kann nicht mehr anders
Ich gebe ja zu, die Zeile 71 ist Geschmacks- und Gewohnheitssache.
Nehmen wir mal die Zeilen 51-53string account; for( Entry e; in >> get_content( ACCOUNT, account ) >> e; ) database[account] = e;
es würde mir echt schwer fallen, satt dessen z.B. so etwas hin zuschreiben:
for(;;) { string account; Entry e; in >> get_content( ACCOUNT, account ); in >> e; if( !in.fail() ) break; database[account] = e; }
ich würde so was hier nicht posten.
SeppJ schrieb:
Werner ist einer der wenigen hier im Forum, die sich richtig gut mit den IOStreams auskennen ..
Auf der einen Seite finde ich das ja nett, dass ich hier als Experte gehandelt werde, aber auf der anderen Seite finde ich gar nicht gut, dass sich nicht viel mehr Leute mit Streams auskennen - und das ist nicht nur im Forum so.
Früher habe ich mal gelernt: Ein Programm ist Eingabe-Verarbeitung-Ausgabe - d.h. Ein- und Ausgabe sind also rudimentär und in jedem Programm vorhanden und das funktioniert in C++ eben mit Stream und Streambuf. Ich fänd's gut wenn mehr Leute damit arbeiten - schon wegen einer gewissen Standardisierung.Gruß
Werner