2017-01-24 2 views
0

Hallo, ich mache ein Programm und in meinem Programm habe ich eine Klasse Kunden. Um den Kunden auf dem Computer zu speichern, erstelle ich eine Datei und separiere alle Daten des Kunden mit :: like name :: password :: phonenbr. Aber mein Problem ist, wenn ich die Zeile schreibe, die im Kommentar zu meinem Code ist, werden die Daten in die Datei gespeichert, aber wenn ich dieselbe Zeile in das if() schreibe, das überprüft, ob die Datei leer ist, tut dies nicht mache alles, obwohl ich mit dem Compiler sehe, dass es mit dieser Zeile kein Problem gibt.Text speichert nicht in der Datei

Wenn Sie mir helfen können, wird es anmutig sein!

void Shop::Add_Customer() 
{ 
    fstream myfile; myfile.open("CustomerFile.txt"); 
    string name, password, phonenbr; 
    string buffer, delimitor = "::"; 

    system("cls"); 
    cout << "Name of the customer: "; cin >> name; 
    cout << "Password of the customer: "; cin >> password; 
    cout << "Phone number of the customer: "; cin >> phonenbr; 

    if (!myfile.is_open()) 
    { 
     myfile.open("CustomerFile.txt", ios::out); 
    } 
    //myfile << name + delimitor + password + delimitor + phonenbr << endl; 

    if (myfile.peek() == std::ifstream::traits_type::eof()) 
    { 
     myfile << name + delimitor + password + delimitor + phonenbr << endl; 
    } 
    else 
    { 
     while (getline(myfile, buffer)) 
     { 
      if (CheckIfCustomerExist(buffer, name, phonenbr) == true) 
      { 
       cout << "Customer already exist" << endl; 
      } 
      else 
      { 
       myfile << name + delimitor + password + delimitor + phonenbr << endl; 
       cout << "Customer insert in the file " << endl; 
      } 
     } 
    } 


} 
+2

off topic: Sie werden es viel einfacher finden, den Parser zu schreiben, um die Datei mit einem einzelnen Zeichenbegrenzer wieder zu lesen. – user4581301

Antwort

0

Der EOF-Flag im Strom gesetzt wird, wenn irgendeine Lese des Stroms fehlschlägt, weil es hinter dem Ende des Stromes zu lesen versucht. Sobald EOF gesetzt ist, ist der Strom in einem schlechten Zustand und kann nicht gelesen oder geschrieben werden, bis das EOF-Flag gelöscht ist.

Hier ist ein wirklich einfaches Beispiel, was los ist:

#include <iostream> 
#include <fstream> 
using namespace std; 

int main() 
{ 
    fstream myfile("CustomerFile.txt", ios::out); 
    if (!myfile.is_open()) 
    { 
     cout << "file not open." << endl; 
    } 
    else 
    { 
     if (myfile.peek() == std::ifstream::traits_type::eof()) 
     { 
      if (myfile.eof()) 
      { 
       cout << "Need to clear the EOF flag." << endl; 
      } 
     } 
    } 
} 

bei EOF späht den EOF-Flag gesetzt, um den Strom in einem Fehlerzustand setzen und es nicht beschreibbar zu machen. Da wir die Datei erweitern wollen, müssen wir mit the aptly named clear method.

#include <iostream> 
#include <fstream> 
using namespace std; 

int main() 
{ 
    fstream myfile("CustomerFile.txt", ios::out); 
    if (!myfile.is_open()) 
    { 
     cout << "file not open." << endl; 
    } 
    else 
    { 
     if (myfile.peek() == std::ifstream::traits_type::eof()) 
     { 
      if (myfile.eof()) 
      { 
       cout << "Need to clear the EOF flag." << endl; 
      } 
      myfile.clear(); 
      if (!myfile.eof()) 
      { 
       cout << "OK. EOF clear now." << endl; 
      } 
     } 
    } 
} 

Off Thema Material, das Flag löschen:

Der folgende Code

while (getline(myfile, buffer)) 
    { 
     if (CheckIfCustomerExist(buffer, name, phonenbr) == true) 
     { 
      cout << "Customer already exist" << endl; 
     } 
     else 
     { 
      myfile << name + delimitor + password + delimitor + phonenbr << endl; 
      cout << "Customer insert in the file " << endl; 
     } 
    } 

für jede Zeile in der Datei wiederholen, Vermutlich überprüfte man den Input-Kunden gegen jeden Kunden in der Datei einzeln. Jedes Mal, wenn der eingegebene Kunde nicht übereinstimmt, wird der eingegebene Kunde zur Datei hinzugefügt. Dies bedeutet, dass der Eingabekunde wahrscheinlich mehrmals zur Datei hinzugefügt wird. Schlimmer noch, das Programm liest und schreibt die gleiche Datei zur selben Zeit und wird wahrscheinlich die Datei korrumpieren.

Es wäre besser zu lesen und zu vergleichen und dann, wenn eine Übereinstimmung nicht gefunden wird, bis zum Ende der Datei vorrücken und den Input-Kunden hinzufügen.

Darüber hinaus ist die Datei geöffnet Logik unnötig kompliziert und noch

fstream myfile; myfile.open("CustomerFile.txt"); 

if (!myfile.is_open()) 
{ 
    myfile.open("CustomerFile.txt", ios::out); 
} 

Den ersten Aufruf fehlschlagen kann, wird sicherlich nicht zu öffnen, wenn die Datei nicht vorhanden ist, um den zweiten Anruf zwingt zu öffnen. Könnte auch einfach die ios::out zu diesem Anruf hinzufügen und damit fertig sein. Der zweite Anruf oben offen aus anderen Gründen fehlschlagen und ist nicht für den Erfolg getestet, so empfehle ich

fstream myfile("CustomerFile.txt", ios::out); 
if (!myfile.is_open()) 
{ 
    perror("file not open: "); 
} 
else 
{ 
    // your code goes here 
} 

Documentation for perror

0

Die Wurzel des Problems liegt in der if-Anweisung Zustand:

(myfile.peek() == std::ifstream::traits_type::eof()) 

Apperantly, Ihre Datei in fstream Modus in der Leitung offen:

fstream myfile; myfile.open("CustomerFile.txt"); 

Jetzt kann ich nur noch herausfinden, warum die Bedingung Ihrer if-Anweisung nicht erfüllt ist, weil die Dateimodi unterschiedlich sind. Ich bin mir nicht sicher, ob ich Recht habe oder nicht (Feedback ist im Kommentarfeld willkommen), aber das ist ein Grund, warum ich mir vorstellen kann.

Ich habe versucht eine meiner eigenen Methoden, die immer funktioniert, und es funktioniert auch für Ihren Code. Ich ersetzte die folgenden Zeilen im Code:

if (myfile.peek() == std::ifstream::traits_type::eof()) 
    { 
     myfile << name + delimitor + password + delimitor + phonenbr << endl; 
    } 

Mit diesen Zeilen:

myfile.seekg (0, ios::end); 
    int length = myfile.tellg(); 

    if (length == 0) 
    { 
     myfile << name + delimitor + password + delimitor + phonenbr << endl; 
    } 

Die erste Zeile myfile.seekg (0, ios::end); wird der Abstand zwischen den zwei Punkten in den Klammern angegeben. 0 und ios :: end sind selbsterklärend; 0 ist der Anfang der Datei und ios :: end ist das Ende der Datei.

Die zweite Zeile int length = myfile.tellg(); speichert den gesuchten Wert in der obigen Zeile in einer int-Variablen namens length. Die Länge ist die Anzahl der Zeichen, die der "Cursor" bewegen müsste, um vom Anfang bis zum Ende dieser Datei zu gelangen. (Stellen Sie sich den Cursor als das blinkende Ding vor, das dem in Microsoft Word ähnelt, das vor dem Wort steht, das Sie sind Eingabe, außer hier kann der Cursor in der Textdatei nicht von Anfang bis Ende verschoben werden.

Diese If-Bedingung ist ziemlich einfach. Wenn die Länge Null ist, bedeutet dies, dass der Cursor 0 Punkte bewegen muss, um vom Anfang der Datei bis zum Ende der Datei zu kommen, und schreiben Sie, was Sie wollen, in diese Datei. Diese Technik hat funktioniert (zumindest hat es für mich getan).

Nebenbei bemerkt gibt es noch einige andere Bereiche, in denen sich Ihr Code verbessern kann. Zum Beispiel, warum hinzugefügt haben diese if-Anweisung:

if (!myfile.is_open()) 
{ 
    myfile.open("CustomerFile.txt", ios::out); 
} 

Dieser Code ist eine Wiederholung dieser Zeilen Code:

fstream myfile; myfile.open("CustomerFile.txt"); 

Der .open() Befehl erfüllt bereits die if-Anweisung Ich wies darauf hin. Wenn die im open() angegebene Datei gefunden wird, wird diese Datei geöffnet. Andernfalls wird die neue Datei weiterhin erstellt. Daher ist diese if-Anweisung redundant und sollte entfernt werden, da sie unnötige CPU-Energie verbraucht und Ihr Programm verlangsamt (nicht viel, aber Sie werden bald erkennen, dass jede Millisekunde Ihren Code ausschöpft; Effizienz ist der Schlüssel). Ich würde Ihnen empfehlen, diese if-Anweisung zu entfernen.

Ein weiteres Problem sind Ihre 3 Variablen, die Sie für die Eingabe akzeptieren. Da sie Strings sind, warum benutzt du die cin >> Methode? Mit cin wird nur das erste Wort in Ihrem Satz verwendet; in der folgenden Zeile:

cout << "Name of the customer: "; cin >> name; 

Wenn Sie John Doe eingeben, wird es nur John auf den Namen Variable speichern, und es wird „Doe“ in die nächste Eingangsgröße bewegen, das Passwort in Ihrem Fall ist. Wenn es kein anderes cin gibt, ignoriert es die Wörter nach dem Leerzeichen. Daher verwenden Sie die folgende Zeile für alle Eingabepunkte:

getline(cin, name); 

Diese Funktion wird alle Worte und Räume als einen einzigen Satz bis zum Punkt erhalten Sie die Eingabetaste drücken, im Gegensatz zu cin, die nur das erste Wort bekommen und ignorieren der Rest des Satzes.

Schließlich sollte Ihre Telefonnummer vom Typ int sein. Ich überlasse das für Sie, um gemäß Ihrer Anforderung zu reparieren.

Ich hoffe, ich beantwortete Ihre Frage und hoffte, dass meine Tipps hilfreich waren. Viel Glück!

EDIT: Ein weiterer Punkt, den ich über Ihren Code verpasste, war, dass Ihre while-Schleife für jede Zeile ausgeführt wird. Das bedeutet, dass es bei jeder einzelnen Zeile der Datei nach dem Namen des jeweiligen Kunden sucht. Das ist nicht was du willst. Sie möchten jede Zeile in der Datei lesen, ABER wenn Sie den Kunden finden, möchten Sie die Funktion beenden, ohne die nächste Zeile fortzusetzen. Außerdem möchten Sie nur dann eine Fehleranweisung ausdrucken, nachdem Sie die gesamte Datei gelesen haben, nicht nur eine einzelne Zeile.

Was dieser Codeabschnitt macht, ist, dass er durch jede Zeile läuft und nach dem Kunden in dieser Zeile sucht. Wenn diese Zeile den Kundendatensatz enthält, setzt sie einen Prüfwert vom Typ int von 0 auf 1, und die break-Anweisung beendet die while-Schleife. Nach dem Lesen der gesamten Datei geht es weiter zu einer if-Anweisung. Wenn in dieser Anweisung die Prüfvariable immer noch 0 ist, bedeutet dies, dass die Datei nicht den Kunden hatte, in dem der neue Datensatz der Datei hinzugefügt wird.

Auch ich sagte, dass die Telefonnummer ein Int-Wert sein sollte. Ich nehme das zurück wie weiter und von anderen StackOverflow-Benutzern eingegeben, die Telefonnummer ist besser als String-Wert geeignet, da sein Format möglicherweise nicht ordnungsgemäß als int-Wert gespeichert wird (z. B. wird 0059875 als 59875 gespeichert).

+0

Der zweite Aufruf von 'open' umfasst den Fehlerfall" Datei existiert nicht ", der nicht durch den ersten Aufruf von' open' abgedeckt wird. Der hinzugefügte 'ios :: out' erzwingt die Erstellung der Datei, falls sie nicht existiert. Es ist also eine Wiederholung, aber der zweite Anruf ist der richtige. – user4581301

+0

Guter Punkt auf den Kundennamen. Stimme nicht zu, wenn die Telefonnummer ein "int" ist. Es sollte wahrscheinlich eine Zeichenkette behalten und auf die richtige Anzahl von Ziffern getestet werden und alle eingegebenen Zeichen sind Ziffern. 'int' wird zum Beispiel keine vorangehende 0 behandeln. – user4581301

+0

Eigentlich ist das wahr @ user4581301, ich habe diesen Aspekt der Telefonnummer nicht berücksichtigt. –

Verwandte Themen