In below mentioned code of function. I am not able to update balance(deposits and withdrawals) in file my.dat. Please advise where am I doing it wrong. (I am a newbie).
void dep_with(int e, int f)
{
int amt;
int recordFind=0;
account ac;
ifstream updatedata("E:\\c++ Project\\final thoughts\\my.dat", ios::in|ios::out);
while(updatedata.read((char*) &ac, sizeof(ac)) && recordFind==0)
{
if(ac.get_account()==e)
{
ac.view_account();
if(f==1)
{
cout<<"\nEnter the amount to be deposited";
cin>>amt;
ac.deposits(amt);
}
if(f==2)
{
cout<<"\nEnter the amount to be withdraw";
cin>>amt;
ac.withdrawls(amt);
}
int pos=(-1)*sizeof(ac);
ofstream updatedata("E:\\c++ Project\\final thoughts\\my.dat", ios::in|ios::out|ios::app);
updatedata.seekp(pos,ios::cur);
updatedata.write((char*) &ac, sizeof(ac));
cout<<"\n\n\tRecord Updated";
recordFind=1;
}
}
updatedata.close();
if(recordFind==0)
{
cout<<"\n\nRecord not Found";
}
}
There are a number of problems here. First, updatedata is a
std::ifstream, which means that it doesn't have functions like write
or seekp. Second, you've opened it in text mode, so you cannot seek
to an arbitrary position in the file; you can only seek to the beginning
or the end, or to a position which was returned by tellg or tellp.
(It's undefined behavior otherwise.) You'll have to memorize the
position before each read, and work from that.) Third, you don't show
the definition of account, but in general, you cannot use
istream::read and ostream::write directly on objects of the type:
you have to format the output and parse the input, using an intermediate
buffer.
EDIT:
I've just noticed that you actually open the file a second time for
writing. This cannot be made to work for several reasons, not the least
of which is that some systems will not allow opening a file with write
access if the file is already open elsewhere. Other than that: you open
with std::ios_base::app, which means that all writes will append to
the end of the file, regardless of where the position marker was before.
In summary:
You need to use an std::fstream.
You need to memorize the position (using tellg) before each read,
and seek back to it if you want to write.
You need to use an intermediate buffer for the data. (This may not
be necessary if 1) the program which reads and writes the data is
compiled with the same compiler, using the same options, on the same
machine, running under the same OS, and 2) the data structure is a pure
POD. These conditions are almost never met in well written C++.)
Related
Seeing a weird crash due to read access violation. Here is the minimal code:
struct MyFile : QFile
{
...
string read ()
{
QByteArray content;
if(<something>)
content = QFile::readAll();
...
string buffer(QFile::size(), 0);
if(content.isEmpty())
{
QFile::seek(offset);
QFile::read(&buffer[0], buffer.size());
}
else
::memcpy(&buffer[0], content.data(), buffer.size());
// ^^^^ 40034 ^^^^ 42690
return buffer;
}
}
Here it's trying to read a .png file. Somehow the QFile::size() returns 42690, while the QFile::readAll() which is stored in content has a size of 40034.
Unfortunately the filename is not handy to verify the actual size. Writing test code for text or png files, it always gives proper results.
How is that possible?
Below is a debug frame for reference:
You code does not take the current file's seek position into account. Thus, in case there were some read operations already, it will crash, because QFile::readAll will return only a part of the file (from the current seek position till the end of file).
The other possibility is the use of QIODeviceBase::Text as mentioned in comments, but you're not using it, so it's not the case.
I need to make a function that every time I click the button, the program read and act according to a line in the log_p.txt file.
However, if I put the read t process inside the function, every time it will read the first line.
void ai_fight::getfile()
{
std::ifstream t("log_p.txt");
ui->pushButton->setEnabled(false);
getline(t, rule);
print_rule(rule);
if(getline(t, p1hand)) print_p1hand(p1hand);
if(getline(t, p1p)) print_p1p(p1p);
if(getline(t, p2hand)) print_p2hand(p2hand);
if(getline(t, p2p)) print_p2p(p2p);
getline(t, announce);
if(announce=="1 eliminated"||announce=="0 eliminated")
{
getline(t, buf);
getline(t, buf);
getline(t, buf);
getline(t, buf);
getline(t, win);
print_win(win);
ui->pushButton->setEnabled(true);
}
else if(announce=="0 winning"||announce=="1 winning")
{
ui->pushButton->setEnabled(true);
}
else qDebug()<<"----------announcement error"<<endl;
ui->pushButton->setEnabled(true);
}
The simplest way is probably to store the ifstream as a class member.
void ai_fight::getfile()
{
if (!m_t.is_open())
m_t.open("log_p.txt");
...
You probably want to close the file when you reach EOF so that you can loop round.
Every time you open a file it will start reading it from the beginning. What you need is to remember the current position in file persistently between function calls. You can achieve it in (at least) two ways:
Open the file outside of the function (e.g. as a class member). This way the file will be opened during the whole execution and the ifstream object will remember the current position.
Store the current position in the file in some variable. You can use tellg and seekg methods to get and set the cursor position in file stream. Of course you need to store this value outside the function.
I'm making this program for class and we are supposed to store objects from a class in a file and then load them. But I always get the last object stored instead of the first. Tried the seekp function but it doesn't work. Also shouldn't the size of an object be 38 bytes, instead of the 48 i'm getting?
void student::load()
{
fstream fin;
fin.open("StudentData.bin",ios::binary|ios::in);
fin.read((char*)this,sizeof(*this));
}
void student::store(int z)
{
fstream fout;
fout.open("StudentData.bin",ios::binary|ios::out);
//fout.seekp(38*z, fout.beg)
cout<<sizeof(*this);
fout.write((char*)this,sizeof(*this));
}
for(i=0;i<count;i++)
{
s[i].store(i);
}
cout<<"Done!";
student pleb;
pleb.load();
pleb.showstudent();
return 0;
}
Your fout.open() rewrites the file each time. If you want to append to file, that is, to have each store() call to write that student after all other students already written, then you can use the ios::app flag.
Or, better, do not open the file in store() at all. Make your store() actuall accept the stream as a parameter; then open the file in the main program (once per all students) and pass the stream to store(). Not only this will solve your problem, but will also make your student class more configurable as it will be easy to write to any file, or in general to any stream the user of student needs.
BTW, also make sure that it is correct to write your students this way. For example, if you have any pointers in your student (including, say, std::string members as they have pointers inside), you will not get what you expect.
As for the object size, it is impossibly to answer not seeing the whole declaration of student class.
I wrote a program, which lets you enter information about a car, and then writes the object on a binary file.
Car car_obj; std::ofstream entr; std::ifstream ex;
void save_data() {
entr.open("main.bin", std::ios::app | std::ios::binary);
car_obj.setInfo(); entr.write((char*)&car_obj, sizeof (car_obj));
entr.close();
}
After this, I have a function which is reading this binary file in order to display all cars which have fuel consumption less than what the user enters (the number is factr in the function arguments).
void vehicles_under_factr(float factr) {
ex.open("main.bin", std::ios::app | std::ios::binary);
while (ex.read((char*)&car_obj, sizeof (car_obj)) && !ex.eof()) {
if (car_obj.fuel_cons < factr) {
car_obj.displayInfo();
}
}
ex.close();
}
It works fine, but only if I have three, or less, objects in my binary file. When there are more than three, it displays the rest as empty fields. As if there is no access after the third car. Why is that so, and what can I do about it?
I feel close to the solution, but my knowledge is limited. Thank you in advance!
no, you can't do this,read((char *)obj, sizeof(obj)),because every object in program have itself memory address, allocate by system. you can't read address
from file .if your object only contain data, it work fine, but if it's element is a object and itself attribute related memory address or iterator(related memory address). it work fail.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Reading from text file until EOF repeats last line
I am writting data to a file using the following code
//temp is class object
fstream f;
f.open ("file", ios::in|ios::out|ios::binary);
for(i=0;i<number_of_employees ;++i)
{
temp.getdata();
f.write( (char*)&temp,sizeof(temp));
}
f.close();
temp is the object of following class
class employee
{
char eno[20];
char ename[20];
char desg[20];
int bpay;
int ded;
public:
void getdata();
void displaydata();
}
But when i write data using this code i find that the last object written to file gets written two times.
my function to read from file is
fstream f;
f.open ("file", ios::in|ios::out|ios::binary);
while(f)
{
f.read((char*)&temp, sizeof(temp));
temp.displaydata();
}
f.close();
following shows my file when it is read till eof
Number :1
Name :seb
Designation:ceo
Basic Pay :1000
Deductions :100
Number :2
Name :sanoj
Designation:cto
Basic Pay :2000
Deductions :400
Number :2
Name :sanoj
Designation:cto
Basic Pay :2000
Deductions :400
What is the cause of this and how can i solve it?
If the problem is repeated output, it's very likely caused by the way you are looping. Please post the exact loop code.
If the loop is based on the data you receive from getdata(), you'll need to look closely at exactly what you input as well. You might not be receiving what you expect.
Of course, without real code, these are almost just guesses.
The reason for your problem is simple: you're not checking whether the
read has succeeded before using the results. The last read encounters
end of file, fails without changing the values in your variables, and
then you display the old values. The correct way to do exactly what
you're trying to do would be:
while ( f.read( reinterpret_cast<char*>( &temp ), sizeof( temp ) ) ) {
temp.displaydata();
}
Exactly what you're trying to do, however, is very fragile, and could
easily break with the next release of the compiler. The fact that your
code needs a reinterpret_cast should be a red flag, indicating that
what you're doing is extremely unportable and implementation dependent.
What you need to do is first, define a binary format (or use one that's
already defined, like XDR), then format your data according to it into a
char buffer (I'd use std::vector<char> for this), and finally use
f.write on this buffer. On reading, it's the reverse: you read a
block of char into a buffer, and then extract the data from it.
std::ostream::write and std::istream::read are not for writing and
reading raw data (which makes no sense anyway); if they were, they'd
take void*. They're for writing and reading pre-formatted data.
Writing an object to a file with write((char*)object, sizeof(object)) is looking for trouble!
Rather write a dedicated write function for the class:
class employee {
...
void write(ostream &out) {
out.write(eno, sizeof(eno));
out.write(ename, sizeof(ename));
out.write(desg, sizeof(desg));
out.write((char*)&bpay, sizeof(bpay));
out.write((char*)&ded, sizeof(ded));
}
void read(istream &in) {
in.read(&eno, sizeof(eno));
in.read(&ename, sizeof(ename));
...
in.read((char*)&bpay, sizeof(bpay));
in.read((char*)&ded, sizeof(ded));
}
}
ostream &operator <<(ostream &out, employee &e) {
e.write(out);
return out;
}
istream &operator >>(istream &in, employee &e) {
e.read(in);
return in;
}
Once you've done that, you can use:
f << temp;
to write your employee record to the file.
But note that even this isn't great, because at least as far as the integers are concerned, we're becoming very platform dependent, ito the size of an int, and ito the endianness of the int.