Hi, could anyone explain to me why the value that I change by using Modify() function does not replace the previous value? It will also occur a lot of meaningless line after that? Assuming that I already have an account by using CreateAccount() and save it to file by using SaveToFile()
void SearchAndModifyAccount(int account_number)
{
bool found = false;
Account account;
fstream file;
file.open("account.dat", ios::binary | ios::in | ios::out);
if (!file)
{
cout << "Khong mo duoc file, hay an phim enter de quay lai menu" << endl;
system("pause");
return;
}
while (!file.eof() && found == false)
{
while (file.read(reinterpret_cast<char*> (&account), sizeof(Account)))
{
// compare account_number with that read from the file
if (account.GetAccountNumber() == account_number) {
account.Modify();
const std::streampos pos = file.tellg();
file.write(reinterpret_cast<char*> (&account), sizeof(Account));
found = true;
}
}
}
file.close();
if (found == false)
cout << "\n\nKhong tim thay tai khoan";
}
1 2 3 4 5 6 7 8 9 10 11
void Account::Modify()
{
cout << "\nNhap thong tin de thay doi:";
cout << "\nTen chu tai khoan: ";
cin.ignore();
cin.getline(name_, 100);
cout << "Loai tai khoan: ";
cin >> type_;
cout << "So du: ";
cin >> balance_;
}
1 2 3 4 5 6 7 8 9 10 11 12
void Account::CreateAccount()
{
cout << "Nhap so tai khoan: ";
cin >> account_number_;
cout << "Nhap ten chu tai khoan: ";
cin.ignore();
cin.getline(name_, 100);
cout << "Nhap loai tai khoan: ";
cin >> type_;
cout << "So du ban dau: ";
cin >> balance_;
}
When I posted that there was no code to accompany your question, so when I posted that there was no way for anyone to help you.
At a glance, it looks like you've never called seekp to place the put cursor in the appropriate place before attempting to write the modified record.
Note that the streampos on line 22 is collected after the read has completed, so it is offset in the stream by sizeof account. It would be simplest to call tellg before the read, and use the result as an argument to seekp.
void SearchAndModifyAccount(int account_number)
{
bool found = false;
Account account;
fstream file;
file.open("account.dat", ios::binary | ios::in | ios::out);
if (!file)
{
cout << "Khong mo duoc file, hay an phim enter de quay lai menu" << endl;
system("pause");
return;
}
while (!file.eof() && found == false)
{
const std::streampos pos = file.tellg();
while (file.read(reinterpret_cast<char*> (&account), sizeof(Account)))
{
// compare account_number with that read from the file
if (account.GetAccountNumber() == account_number) {
account.Modify();
}
}
file.seekp(pos);
file.write(reinterpret_cast<char*> (&account), sizeof(Account));
found = true;
}
file.close();
if (found == false)
cout << "\n\nKhong tim thay tai khoan";
}
But seem like it didn't print it out in "account.dat". So I wonder what wrong in my logic here?
> But seem like it didn't print it out in "account.dat". So I wonder what wrong in my logic here?
When in doubt, prototype!
Whenever you're stuck, or are unsure about a new concept, then creating a mini side project just to explore is quick and easy. It's certainly a lot quicker and easier than trying to analyse it deep within some larger project.
Create the most basic Account possible (just an ID) and try your various modes of operation.
#include <iostream>
#include <fstream>
#include <iomanip>
usingnamespace std;
class Account {
int m_id;
public:
int setID(int id) { m_id = id; }
int getID() { return m_id; }
};
int main()
{
constint nRec = 5;
Account account;
fstream file;
file.open("account.dat", ios::binary | ios::in | ios::out);
if ( !file.is_open() ) {
cerr << "Oops" << endl;
return 1;
}
// Writing
for ( int i = 0 ; i < nRec ; i++ ) {
account.setID(i);
if ( file.write(reinterpret_cast<char*>(&account), sizeof(Account)) ) {
cout << "Wrote record " << i << endl;
} else {
cerr << "Write fail" << endl;
}
}
file.flush(); // Flush between write and read
cout << "Read Pos=" << file.tellg() << endl;
cout << "Write Pos=" << file.tellp() << endl;
// Reading
file.seekg(0);
for ( int i = 0 ; i < nRec ; i++ ) {
if ( file.read(reinterpret_cast<char*>(&account), sizeof(Account)) ) {
cout << "Account" << i << "=" << account.getID() << endl;
} else {
cerr << "Read 1 fail" << endl;
}
}
cout << "Read Pos=" << file.tellg() << endl;
cout << "Write Pos=" << file.tellp() << endl;
// Finding and updating a specific record
file.seekg(0);
while ( file.read(reinterpret_cast<char*>(&account), sizeof(Account)) ) {
cout << "R=" << account.getID() << endl;
if ( account.getID() == nRec/2 ) {
account.setID(42);
file.seekp(-sizeof(Account),ios_base::cur);
file.write(reinterpret_cast<char*>(&account), sizeof(Account));
file.flush(); // Flush between write and read
}
}
// Reading again
file.clear(); // Because the while loop may have run into end of file
file.seekg(0);
for ( int i = 0 ; i < nRec ; i++ ) {
if ( file.read(reinterpret_cast<char*>(&account), sizeof(Account)) ) {
cout << "Account " << i << "=" << account.getID() << endl;
} else {
cerr << "Read 2 fail" << endl;
}
}
return 0;
}
$ g++ foo.cpp
$ ./a.out
Wrote record 0
Wrote record 1
Wrote record 2
Wrote record 3
Wrote record 4
Read Pos=20
Write Pos=20
Account0=0
Account1=1
Account2=2
Account3=3
Account4=4
Read Pos=20
Write Pos=20
R=0
R=1
R=2
R=3
R=4
Account 0=0
Account 1=1
Account 2=42
Account 3=3
Account 4=4
void SearchAndModifyAccount(int account_number)
{
bool found = false;
Account account;
fstream file;
file.open("account.dat", ios::binary | ios::in | ios::out);
if (!file)
{
cout << "Khong mo duoc file, hay an phim enter de quay lai menu" << endl;
system("pause");
return;
}
while (!file.eof() && found == false)
{
file.seekg(0);
const std::streampos pos = file.tellg();
while (file.read(reinterpret_cast<char*> (&account), sizeof(Account)))
{
// compare account_number with that read from the file
if (account.GetAccountNumber() == account_number) {
char choice;
account.PrintAccount();
cout << "\nDo you want to change info or keep?";
cin >> choice;
if (choice == 'Y')
{
account.Modify();
file.seekp(sizeof(Account), ios_base::cur);
file.seekp(pos);//for writing positioning
file.write(reinterpret_cast<char*>(&account), sizeof(Account));
file.flush();
found = true;
}
elseif (choice == 'N')
{
Menu();
}
}
}
}
file.close();
if (found == false)
cout << "\n\nKhong tim thay tai khoan";
}
So it will not only modify the previous info but also replace it? Am I right? I already check it and it work when just one account. But if more than one, for example 3 accounts. If I try to change the info of the account, it will change the first one? Is it because of file.seekg(0);
P/s: But if I remove the else if() it work normally
But seem like it didn't print it out in "account.dat".
What made you think so?
Actually it is just my doubt about it so I don't have any hypothesis then I just told what I took just because I did not see anything error in debugger.
Yes, remove line 17. Line 30 doesn't make sense either.
Why line 30 makes no sense? I think it calls the Modify() function, doesn't it?
1 2 3 4 5 6 7 8 9 10 11
void Account::Modify()
{
cout << "\nNhap thong tin de thay doi:";
cout << "\nTen chu tai khoan: ";
cin.ignore();
cin.getline(name_, 100);
cout << "Loai tai khoan: ";
cin >> type_;
cout << "So du: ";
cin >> balance_;
}
while (!file.eof() && found == false)
{
file.seekg(0);
const std::streampos pos = file.tellg();
while (file.read(reinterpret_cast<char*> (&account), sizeof(Account)))
1. Two nested while loops are wrong. You only need one while loop to examine every record in the file.
2. your 'pos' is both declared const, and also set up once.
> file.seekp(pos);//for writing positioning
So when you do this, you always overwrite the FIRST record.
1 2 3 4
elseif (choice == 'N')
{
Menu();
}
No, don't call Menu() recursively, just return back to it.
Seriously... rather than simply telling us things about how your program works, why don't you investigate it yourself? Why don't you step through it in your debugger, and look at what's going on, and see why it's not reaching the account you want.
#coder777
Thanks a lot for yoru help! I think that it is the same method as the function that you explained to me yesterday. If my question mind you so much, just tell me and I will improve it. One more time, thank you for that.
#MikeyBoy
Sorry if my question bother that much. I apologize!
> #salem c why do we need a minus before sizeof(Account) in file.seekp in line 5? Do we have any reason for that?
Yes, you read post http://www.cplusplus.com/forum/general/262310/#msg1133822 where I show what happens when you leave it out, and the subsequent change in which record gets overwritten.
Sorry if my question bother that much. I apologize!
It's that there are tools you could learn to use that would help you discover the reasons why your code isn't behaving the way you want it to, and help you discover how to fix it, if only you'd learn to use them.
Don't you want to be able to fix your own problems?
Don't you want to be able to be a better programmer?