简体   繁体   中英

Text doesn't save into the file

Hello I do a program and in my program I have a class Customer. In order to save the customer on the computer I create a file and separate every data of customer with :: like name::password::phonenbr. But my problem is if I write the line that is in the comment on my code the data will be save into the file, but If I write the same line in the if() that checks if t the file is empty this doesn't do anything although that I see with the compiler that there is no problem with this line.

If you can help me it will be graceful !

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;
            }
        }
    }


}

The EOF flag in the stream is set when any read of the stream fails because it tried to read past the end of the stream. Once EOF is set the stream is in a bad state and cannot be read or written until the EOF flag is cleared.

Here is a really simple example of what is going on:

#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;
            }
        }
    }
}

Peeking at EOF set the EOF flag, putting the stream in an error condition and making it unwritable. Since we want to extend the file, we need to clear that flag with 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 topic stuff:

The following 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;
        }
    }

will repeat for every line in the file, presumably checking the input customer against every customer in the file one by one. Every time the input customer does not match, the input customer will be added to the file. This means the input customer is likely to be added to the file several times. Worse, the program is reading and writing the same file at the same time and will probably wind up corrupting the file.

It would be better to read and compare and then if a match is not found advance to the end of the file and add the input customer.

In addition, the file open logic is needlessly complicated and may still fail

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

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

The first call to open will certainly fail if the file is not present, forcing the second call to open. Might as well just add the ios::out to this call and be done with it. The second call top open may fail for other reasons and is not tested for success, so I recommend

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

Documentation for perror

The root of your problem lies in your if-statement's condition:

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

Apperantly, your file is open in fstream mode in the line:

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

Now the only reason I can get for why your if-statement's condition is not met is because the file modes are different. I'm not sure whether I am right or not (feedback is welcome in the comments box), but that's a reason I can come up with.

I tried one of my own methods that always works, and it worked for your code also. I replaced the following lines in your code:

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

With these lines:

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

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

The first line myfile.seekg (0, ios::end); gets the distance between the 2 points specified in the brackets. 0 and ios::end are self explanatory; 0 is the start of the file and ios::end is the end of the file.

The second line int length = myfile.tellg(); stores the value seeked in the above line in an int variable called length. The length is the number of characters the "cursor" would have to move to get from start to end of this file (try to imagine the cursor as the blinking thing similar to the one in Microsoft Word that is in front of the word you are typing, except here, you cannot see the cursor in your text file moving from start to end).

This if-condition is pretty straightforward. If the length is zero, meaning that the cursor has to move 0 points to get from the start of the file to the end of the file, then write whatever you want to that file. This technique worked (at least it did for me).

On a side note, there are a couple of other areas where your code can improve. For example, why have you added this if-statement:

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

This code is a repetition of these lines of your code:

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

The .open() command already fulfills the if-statement I pointed out. If the file specified in the open() is found, then it will open that file; else it will continue to create that new file. Therefore, that if-statement is redundant and should be removed as it consumes unnecessary CPU power and slows your program down (not by a lot, but you will soon realize that every millisecond counts in running your code; efficiency is key). I would recommend you to remove that if-statement.

Another issue is your 3 variables that you accept for input. Given that they are strings, why do you use the cin >> method? Using cin will only take the first word in your sentence; in your following line:

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

If you enter John Doe , it will only save John to the name variable, and it will move "Doe" to the next input variable, which is password in your case. If there is no other cin, then it will ignore the words after the space. Therefore, use the following line for all your input points:

    getline(cin, name);

This function will get all the words and spaces as a single sentence till the point you hit Enter, unlike cin that will only get the first word and ignore the rest of the sentence.

Finally, your phone number should be of type int. I'll leave that for you to fix as per your requirement.

Hope I answered your question and hoped my tips were helpful. Good luck!


EDIT: Another point I missed about your code was that your while loop runs for every line. This means it will check for the particular customer's name at every single line of the file. This is not what you want. You want to read every line in the file, BUT if you find the customer, then you want to terminate the function without continuing for the next line. Also, you only want to print an error statement AFTER you have read the entire file, not just a single line.

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

What this piece of code does is that it runs through every line, checking for the customer in that line. If that line has the customer record, then it sets an check value of type int to 1 from 0 and the break statement terminates the while loop. After reading the entire file, it moves on to an if-statement. In this statement, if the check variable still has 0, it means that the file did not have the customer, in which the new record will be added to the file.

Also, I said that the phone_number should be an int value. I take that back as upon further though and input from fellow StackOverflow users, the phone number is better suited as a string value as its format may not be stored properly as an int value (for example, 0059875 will be stored as 59875).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM