need help with struct i/o please

Started by
1 comment, last by Oluseyi 19 years, 3 months ago
i have two files, master.dat and trans.dat. i want to open both and update the master file with the data on the trans file. if there is no match i want to add the data to the end of file. however when i read back the file at the end of my program it looks updated but only to those that matched. no new data is added. i think i have stared at it too long now. help please?

#include<iostream>
using namespace std;

#include<fstream>
using std::ofstream;
using std::ifstream;

#include<string>

struct record
{
	char name[15];
	float amnt;
};

void main()
{

	fstream mf("master.dat", ios::in | ios::binary); //master file
	fstream mc("masterec.dat", ios::out | ios::binary); //copy of master
	fstream tf("trans.dat", ios::in | ios::binary); //trans file

	record master,trans;

	while(mf.read((char*)&master, sizeof(master))) 
	{
		mc.write((char*)&master, sizeof(master)); //write copy 
	}

	mf.close();//close master
	mc.close();//close copy

	mc.open("masterec.dat", ios::in | ios::out | ios::binary); //open in read/write mode

	long int recsize = sizeof(record);

	for (int i = 0; i < 6; i++) 
	{	
		int found = 0;//flag
		
		tf.seekg(i*recsize, ios::beg); //record we are working on trans
		tf.read((char*)&trans, sizeof(trans)); //read in

		mc.seekg(0, ios::beg); //move to beg of file

		while(mc.read((char*)&master, sizeof(master)))
		{
			if(strcmp(trans.name, master.name) == 0) //check for match
				{
					mc.seekg(-recsize, ios::cur); //back up one
					master.amnt += trans.amnt; //update

					cout << "updated " << master.name << " to " << master.amnt << endl;

					mc.write((char*)&master, sizeof(master));
					found = 1;
					break;
				}
		}

			mc.clear();

		if(found == 0)
				{
					mc.seekg(0, ios::end);
					cout << "no match for "<< trans.name << " " << trans.amnt << endl;	
					mc.write((char*)&master, sizeof(master)); //write to file
				}
		}


	tf.close();

	mc.clear();
	mc.seekg(0, ios::beg);

	cout <<"Master file now reads=\n";

	while(mc.read((char*) &master, sizeof(master)))
	{
		cout << master.name << " " << master.amnt << endl;
	}

	mc.close();
}

edit: added [source] tags -SiCrane
Advertisement
First thing I thought I'd point out a little common-practice trick that might help you along. You're using C++ (ifstream and ofstream), so instead of using an int for your "found" flag, which is always either one of two values, I recommend using the "bool" type (boolean), which is defined as either being true or false. The reason for this is just that it makes the immediate readability of your code clearer. Your comments are good and almost do this job, but sometimes they won't. Use a bool, what you're doing there is precisely what they are defined for. Then you can have neat lines like this...

bool myFlag = true;if (myFlag){ /* do impressive stuff here */ }


Also, for sake of naming convention, "masterec.dat" is remarks as being a "copy" of master.dat, but after program execution it is no longer a copy. This may seem obvious. All the more reason to include a comment. (Comments will save you some day. There would be no fancy games without comments.)

Now, you already have a fair amount of debug stuff in your code, but I don't know if you're looking at it that way or not. You say that after execution the file seems to be modified appropriately but *only* where records initially existed, not at the end of the file. That is, no new records are being appended. Here is what I think you should do:

1. in your final if-clause (if (found==0)), you seek to the end of the file, report that there was no match found for the immediate record (echoing the record), and then you write to the file. Are you ever seeing the text "no match for..."? That is, if that cout line is never being triggered, that means the found-flag is never being set to 1 as it should be. As I look at your code I don't believe this is your error, but this is the sort of strategy you should be formulating as you debug: Is the program really doing what you think it is doing? You can go line by line having the program couting everything you want it to just to see what is going on when, then pull the needless couts when the program works. (We all do this kind of thing, even for fancy games. In fact, there would be no fancy games if not for logging of this nature. =))

If you want further help from us in this venue, please post the output you're getting. One of us may be able to point you in the right direction.

2. This is the hard bit of truth that you need to know. C++ file i/o is "FUNKY." That is, it doesn't always work they way you think it should, and that can be largely based on the compiler you are using. For example, I have *never* been able to get the get() and getline() functions to do what they say they do. I use read() and write() as you do. I know people who have the exact trouble I do. I know people who have that trouble reversed. That said, the fact that you're getting close to the output you want (and that you're using the same enviroment I do, I think - ms visual c++) you should stick with that set of functions. If you're not using MS Vis C++, you might consider using the other "set" of i/o functions in fstream. I don't think you should, but that may be what's up.

3. Worst case, I would close the damned file and reopen it as ios::app after your editting loop, then just tag on the rebel records after your first loop. This is extraordinarily inefficient, but when I get frustrated (personally) I find myself willing to become inefficient if it is effective.

That said, what you should really do is talk to your professor.

I understand you work and that the hours your professor holds don't match with yours. Skip a night of sleep or a day of work or schedule a nap. Talk to your professor. I am in my professors' offices every day during the semester. They all know me *very* well, because I ask them *everything* that comes to mind. And it helps. It's the reason I passed Assembly and Architecture. It's the reason I will pass my calc courses (which I fear). Talk to your professor.

Anyway I hope this helps. Add lots of cout lines so you see just what is going on when, make sure it's doing what you think it should be doing. Good luck.

[EDIT - I just realized this was posted the 5th of December...which implies that your semester is over now. I hope you figured this out. Sorry I didn't see it sooner.]
To copy the contents of one C++ stream (istream) to another (ostream), consider using std::copy, std::istream_iterator and std::ostream_iterator:
#include <algorithm>#include <fstream>#include <iostreamint main(int argc, char *argv[]){  using namespace std;  // I simply assume that the command line parameters are accurate and valid here  // for sake of example. You should do data validation in your production code.  ifstream fin(argv[1]);  ofstream fout(argv[2]);  copy(istream_iterator<char>(fin),       istream_iterator<char>(),       ostream_iterator<char>(fout));  // Strictly speaking, the next two lines are superfluous since the program exits.  fin.close();  fout.close();  return 0;}
Note that istream_iterator and ostream_iterator are for formatted output. The <algorithm> header contains a lot of useful solutions to common programming tasks, so it's worth your while to look through it, particularly with a good reference at hand.

Moving on to the second part of your problem, the first thing I notice in your code is that you never clear the status bits on mc. That doesn't appear to be a problem in this case, since you were writing to out and, consequently, it didn't hit an EOF, but it's a good habit to get into when reopening stream objects.

The second big problem I see is that you seem to think that C++ streams are sufficiently dynamic to support insertion of new data. They aren't. If you wish to insert arbitrary data/text at a certain point in a file via a C++ stream, you must copy from the top of the file to the insertion point to a new (temporary) file, insert the new data/text, then copy from the insertion point to the end of the original file to the new file. Finally, you must close and delete the original file and rename the new file to the original.

With these in mind, I'm sure you can write a much better program. Happy hacking!

This topic is closed to new replies.

Advertisement