你好,我做了一个程序,在我的程序中,我有一个类Customer。 为了将客户保存在计算机上,我创建了一个文件,并将客户的每个数据与:: like name :: password :: phonenbr分开。但我的问题是,如果我在我的代码的注释中写入行将数据保存到文件中,但是如果我在if()中写入相同的行来检查文件是否为空这不是做任何事情虽然我在编译器中看到这条线没有问题。
如果你可以帮助我,那将是优雅的!
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;
}
}
}
}
答案 0 :(得分:0)
当流的任何读取失败时,将设置流中的EOF标志,因为它尝试读取流的末尾。一旦设置了EOF,流就处于错误状态,并且在清除EOF标志之前无法读取或写入。
以下是一个非常简单的示例:
#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;
}
}
}
}
在EOF处偷看设置EOF标志,使流处于错误状态并使其不可写。由于我们要扩展文件,因此需要使用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;
}
}
}
}
关闭主题:
以下代码
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;
}
}
将重复文件中的每一行,大概是逐个检查输入客户对文件中的每个客户。每次输入客户不匹配时,输入客户将被添加到文件中。这意味着输入客户可能会多次添加到文件中。更糟糕的是,该程序正在同时读取和写入同一个文件,最终可能会破坏文件。
最好先阅读和比较,然后如果找不到匹配项,请提前到文件末尾并添加输入客户。
此外,文件打开逻辑不必要地复杂并且可能仍然失败
fstream myfile; myfile.open("CustomerFile.txt");
if (!myfile.is_open())
{
myfile.open("CustomerFile.txt", ios::out);
}
如果文件不存在,第一次打开open肯定会失败,迫使第二次调用打开。也可以将ios::out
添加到此调用中并完成它。第二个呼叫顶部打开可能由于其他原因而失败,并且未经过成功测试,因此我建议
fstream myfile("CustomerFile.txt", ios::out);
if (!myfile.is_open())
{
perror("file not open: ");
}
else
{
// your code goes here
}
答案 1 :(得分:0)
问题的根源在于if语句的条件:
(myfile.peek() == std::ifstream::traits_type::eof())
显然,你的文件在fstream模式下打开了行:
fstream myfile; myfile.open("CustomerFile.txt");
现在我唯一能解决为什么不满足if语句条件的原因是因为文件模式不同。我不确定我是否对(欢迎在评论栏中提供反馈),但这是我能想到的原因。
我尝试了一种始终有效的方法,它也适用于您的代码。我在您的代码中替换了以下行:
if (myfile.peek() == std::ifstream::traits_type::eof())
{
myfile << name + delimitor + password + delimitor + phonenbr << endl;
}
使用这些行:
myfile.seekg (0, ios::end);
int length = myfile.tellg();
if (length == 0)
{
myfile << name + delimitor + password + delimitor + phonenbr << endl;
}
第一行myfile.seekg (0, ios::end);
获取括号中指定的2个点之间的距离。 0和ios :: end是自解释的; 0是文件的开头,ios :: end是文件的结尾。
第二行int length = myfile.tellg();
将上面一行中搜索到的值存储在名为length的int变量中。长度是“光标”从此文件的开头到结尾移动所需的字符数(尝试将光标想象为与您在单词前面的Microsoft Word中类似的闪烁事物键入,除了这里,你不能看到文本文件中的光标从头到尾移动)。
这个if条件非常简单。如果长度为零,则意味着光标必须移动0个点才能从文件的开头到文件的末尾,然后将所需的内容写入该文件。这种技术起作用(至少它对我有用)。
另外,还有一些其他方面可以改进您的代码。例如,为什么要添加这个if语句:
if (!myfile.is_open())
{
myfile.open("CustomerFile.txt", ios::out);
}
此代码重复了以下代码行:
fstream myfile; myfile.open("CustomerFile.txt");
.open()命令已经完成了我指出的if语句。如果找到open()中指定的文件,那么它将打开该文件;否则它将继续创建该新文件。因此,if语句是冗余的,应该被删除,因为它消耗了不必要的CPU功率并减慢了程序的速度(不是很多,但你很快就会意识到运行代码每一毫秒都是重要的;效率是关键)。我建议你删除那个if语句。
另一个问题是您接受输入的3个变量。鉴于它们是字符串,为什么要使用cin&gt;&gt;方法?使用cin只会占用你句子中的第一个单词;在您的以下行中:
cout << "Name of the customer: "; cin >> name;
如果你输入 John Doe ,它只会将John保存到name变量,它会将“Doe”移动到下一个输入变量,即你的密码。如果没有其他cin,那么它将忽略空格后的单词。因此,对所有输入点使用以下行:
getline(cin, name);
这个函数会将所有的单词和空格作为单个句子,直到你点击Enter为止,不像cin那样只得到第一个单词并忽略句子的其余部分。
最后,您的电话号码应为int类型。我会留下那个让你根据你的要求修复。
希望我回答了你的问题,并希望我的建议有所帮助。祝你好运!
编辑:我错过了你的代码的另一点是你的while循环运行每一行。这意味着它将在文件的每一行检查特定客户的名称。这不是你想要的。您想要读取文件中的每一行,但是如果找到客户,那么您希望在不继续下一行的情况下终止该功能。此外,您只想在读取整个文件后打印错误语句,而不只是一行。
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;
}
}
这段代码的作用是它贯穿每一行,检查该行中的客户。如果该行具有客户记录,则它将类型int的检查值从0设置为1,并且break语句终止while循环。读完整个文件后,它会转到if语句。在此语句中,如果check变量仍为0,则表示该文件没有客户,新记录将添加到该文件中。
另外,我说phone_number应该是一个int值。我将其作为进一步的反馈并从StackOverflow用户输入,电话号码更适合作为字符串值,因为其格式可能无法正确存储为int值(例如,0059875将存储为59875)。