Datei ein zweites mal öffnen ohne das alles weg ist.



  • Moin Leute,
    ich hab ein Problem, nachdem ich etwas in meine Datei gespeichert habe und sie dann ein zweites mal öffne ist sie entweder leer oder sie öffnet sich nicht mehr. Kann mir wer sagen was ich falsch gemacht habe oder was ich hinzufügen muss damit ich die Sachen in einer Datei nach dem schließen nochmal bearbeiten/erweitern kann. Soweit ich weis muss die Funktion "holeDaten" geändert werden damit es funktioniert.

    #include <iostream>
    #include <string>
    #include <fstream>
    
    using namespace std;
    
    fstream file;
    struct textspeicher {
        string wert;
        string status = "O"; 
        textspeicher* naechster = NULL;
    };
    
    textspeicher* kopf = new textspeicher;
    
    void elementHinzufuegen(textspeicher* hinzuzufuegendesElement) {
        textspeicher* temp = kopf;
        while(temp->naechster != NULL) {
            temp = temp->naechster;
        }
        temp->naechster = hinzuzufuegendesElement;
    }
    
    void allesAusgeben(){
        textspeicher* temp = kopf;
        while(temp->naechster != NULL){
            temp = temp->naechster;
            cout << temp->status << " " << temp->wert << endl;
     
        }
        cout << endl;
    }
    
    void elementLoeschen(textspeicher* zuLoeschendesElement) {
        textspeicher* temp = kopf;
        while(temp->naechster != zuLoeschendesElement){
            temp = temp->naechster;
        }
        temp->naechster = zuLoeschendesElement->naechster;
    }
    
    int anzahlDaten(){
        textspeicher* temp = kopf;
        int Anzahl = 0;
        while (temp->naechster != NULL)
        {
            temp = temp->naechster;
            Anzahl++;
        }
        return Anzahl;
    }
    
    void ErledigtUnerledigt(textspeicher* zuAenderndesElement){
        textspeicher* temp = kopf;
        while(temp->naechster != zuAenderndesElement){
            temp = temp->naechster;
        }
        if(temp->naechster->status == "O"){
            temp->naechster->status = "X";
        }
        else if(temp->naechster->status == "X"){
            temp->naechster->status = "O";
        }
    }
    
    void EintragUmbenennen(textspeicher* zuUmbenennendesElement){
        textspeicher* temp = kopf;
        string neuerName;
        while(temp->naechster != zuUmbenennendesElement){
            temp = temp->naechster;
        }
        cout << "Wie willst du den Eintrag umbenennen?" << endl;
        cin >> neuerName;
        temp->naechster->wert = neuerName;
    }
    
    textspeicher* findeEintragDurchText(string zuSuchenderText){
        textspeicher* temp = kopf;
        while (temp->wert != zuSuchenderText) {
            temp = temp->naechster;
        }
        return temp;
    } 
    
    void holeDaten(){
        textspeicher* temp = kopf;
        string zeile;
        file.open("daten.txt", ios::in | ios::out);
        if (file.fail()){
            cout << "Fehler beim Oeffnen der Datei." << endl;
        }
        while(!file.eof()){
            while(getline(file,zeile,',')){
                cin >> temp->naechster->wert;
                temp = temp->naechster;
            }
            while(getline(file,zeile,'\n')){
                cin >> temp->naechster->status;
                temp = temp->naechster;
            }
        }
        file.close();
    }
    
    int main() {
        kopf->wert = "Beginn";
        kopf->naechster = NULL;
        int eingabe;
        int schleife = 0;
    
        holeDaten();
        
        while(schleife == 0) {
    
            cout << endl;
            cout << "Anzahl der Daten: " << anzahlDaten() << endl;
            cout << "1. Eintrag hinzufuegen" << endl;                           // Fertig
            cout << "2. Eintrag loeschen" << endl;                              // Fertig
            cout << "3. Eintrag umbenennen" << endl;                            // Fertig
            cout << "4. Eintrag als erledigt oder unerledigt ändern" << endl;   // Fertig
            cout << "5. Eintrag durch Text finden" << endl;                     
            cout << "6. Alle Daten ausgeben" << endl;                       // Fertig
            cout << "7. Programm beenden" << endl;                              // Fertig
            cin >> eingabe;
    
            if (eingabe == 1) {
                system("cls");
                int num = 0;
                cout << "Wie viele Daten sollen hinzugefuegt werden?" << endl;
                cin >> num;
    
                for (int i = 0; i < num; i++){
                textspeicher* tmp = new textspeicher;
                cout << "Bitte geben Sie den " << i+1 <<" Eintrag ein: " << endl;
                cin >> tmp->wert;
                elementHinzufuegen(tmp);
                }
            }
            else if (eingabe == 2) {
                system("cls");
                int num = 0;
                cout << "Bitte waehle eine Nummer von 1 bis " << anzahlDaten() << endl;
                allesAusgeben();
                cin >> num;
    
                textspeicher* tmp = kopf;
                for (int i = 0; i < num; i++)
                {
                    tmp = tmp->naechster;
                }
                elementLoeschen(tmp);
            }
            else if (eingabe == 3){
                textspeicher* temp = kopf;
                int num = 0;
                system("cls");
                cout << "Bitte waehle eine Nummer von 1 bis " << anzahlDaten() << " die du umbenennen willst" << endl;
                allesAusgeben();
                cin >> num;
    
                textspeicher* tmp = kopf;
                for (int i = 0; i < num; i++)
                {
                    temp = temp->naechster;
                }
                EintragUmbenennen(temp);
     
            }
            else if(eingabe == 4){
                textspeicher* tmp = kopf;
                system("cls");
                int num = 0;
                cout << "Bitte waehle eine Nummer von 1 bis " << anzahlDaten() << endl;
                allesAusgeben();
                cin >> num;
                
                for (int i = 0; i < num; i++)
                {
                    tmp = tmp->naechster;
                }
                ErledigtUnerledigt(tmp);
            }
            else if(eingabe == 5){
                system("CLS");
                allesAusgeben();
                string num;
                cout << "Von welchem Text moechtest du den Eintrag finden?" << endl;
                cin >> num;
                cout << "Der Eintrag befindet sich hier: " << findeEintragDurchText(num) << endl;
            }
            else if(eingabe == 6){
                system("CLS");
                allesAusgeben();
            }
            else if(eingabe == 7){  
                textspeicher* temp = kopf;
                file.open("daten.txt", ios::out);
                if (file.fail()){
                    cout << "Fehler beim Oeffnen der Datei." << endl;
                }
                file.clear();
                while(temp->naechster != NULL){
                    file << temp->naechster->wert << "," << temp->naechster->status << endl;
                    temp = temp->naechster;
                }
                file.close();
                cout << "Das Programm wird jetzt beendet" << endl;
                schleife++;
            }else{
                cout << "Bitte geben sie eine gueltige Nummer an!" << endl;
    
            }
        }
    }
    
    


  • Beim ios::out wird die Datei zum Neuschreiben geöffnet.
    Die Länge wird auf 0 und der Dateizeiger auf den Anfang der Datei gesetzt.

    (Der Dateizeiger ist ein Hilfskonstrukt innerhalb des IO-Systems. Um die Position zu ändern gibt es Befehle oder Methoden, die irgendwas mit seek heißen. tellgibt dann die Position zurück)



  • Wenn du als Flags ios::app und ios::ate angibst werden neue Daten angehängt.
    ios::app bedeutet "append", ios:ate bedeutet "at the end".



  • Genereller Rat: keine globalen Variablen! Es gibt keinen Grund dafür, dass "file" global ist! (und textspeicher auch nicht)

    Nimm die spezialisierten Streams, wenn du lesen willst oder wenn du schreiben willst, dann kannst du dir das Geraffel mit ios::irgendwas oft sparen.

    Zum Einlesen nimmst du einfach einen ifstream. Bei einer Textdatei würde ich mich immer entscheiden: reinschreiben oder auslesen - denn ansonsten musst du, dank variabler Zeilenlängen, eh die ganze Datei ab der Änmderung neu schreiben.

    Eine while (!file.eof)-Schleife ist praktisch immer verkehrt, da du erst testest, ob du hinter das Dateiende versucht hast zu lesen (genau das sagt dir das EOF, es sagt dir nicht, dass du jetzt am Ende bist), bevor du es dann möglicherweise doch tust. Du musst so einlesen, wie du das innerhalb der Schleife gemacht hast, also while (einlesen_erfolgreich) verarbeite_wert();.

    Dein holeDaten liest erst kommagesplittet ein. Danach ist NICHTS mehr übrig. Die Schleife danach tut somit nichts mehr, da keine Daten mehr vorliegen.

    Überhaupt ist mir unklar, was das holeDaten machen soll. Einerseits liest es irgendwie aus der Datei ein, andererseits liest es aber auch von cin, und zwar so oft, wie es Kommas in der Datei gibt (+1). Und woher weißt du, dass deine Liste so lang ist?



  • @MadDevil sagte in Datei ein zweites mal öffnen ohne das alles weg ist.:

    struct textspeicher {
    string wert;
    string status = "O";
    textspeicher* naechster = NULL;
    };

    textspeicher* kopf = new textspeicher;

    Warum nutzt du kein std::vector?



  • @Quiche-Lorraine hatten wir in der Schule noch nicht.



    1. Prüfen
    2. Lesen
    3. Verarbeiten

    immer falsch sein.

    1. Lesen
    2. Prüfen
    3. Verarbeiten

    du musst.



  • @Swordfish Kannst du das nochmal so formulieren das ich das verstehen kann.


  • Mod

    @MadDevil sagte in Datei ein zweites mal öffnen ohne das alles weg ist.:

    @Swordfish Kannst du das nochmal so formulieren das ich das verstehen kann.

    Der Arbeitsablauf

    1. Prüfen
    2. Lesen
    3. Verarbeiten

    ist immer falsch.

    Richtig ist

    1. Lesen
    2. Prüfen
    3. Verarbeiten

    siehe auch schon weiter oben:

    @wob sagte in Datei ein zweites mal öffnen ohne das alles weg ist.:

    Eine while (!file.eof)-Schleife ist praktisch immer verkehrt, da du erst testest, ob du hinter das Dateiende versucht hast zu lesen (genau das sagt dir das EOF, es sagt dir nicht, dass du jetzt am Ende bist), bevor du es dann möglicherweise doch tust. Du musst so einlesen, wie du das innerhalb der Schleife gemacht hast, also while (einlesen_erfolgreich) verarbeite_wert();.

    Das gilt nicht nur für das Lesen von Dateien, sondern für alle Aktionen, die irgendwie fehlschlagen können. Denn erstens kann man nicht alles prüfen, und zweitens kann sich zwischen Prüfung und Aktion der Zustand, den man geprüft hat, ändern. Daher immer eine Aktion einfach versuchen, dann prüfen, ob es geklappt hat.

    Ausnahmen darf man machen, wenn bei einer unerlaubten Aktion buchstäblich das Flugzeug abstürzen würde oder das Kraftwerk explodiert. Aber nichts was man an einem normalen Heimcomputer macht.

    Besonders falsch ist es bei der bemängleten while (!file.eof)-Schleife , denn da ergibt es nicht einmal Sinn, selbst wenn man obige Begründung vernachlässigt. eof prüft, ob die vorherige Leseaktion an das Ende gestoßen ist, nicht ob die nächste Leseaktion an das Ende stoßen würde (Wie sollte eof das auch wissen? Es kann ja gar nicht wissen, was kommen wird). Daher ergibt eof als Vorprüfbedingung überhaupt gar keinen Sinn.


Log in to reply