Binary file reading problems?

I'm having trouble when it comes to reading from a binary file within a function after writing to it in a previously used function. The function writes an instance of a class to a spot in the binary file determined by a member of the class, itemID.

The class and binary file variable are initialized here.
1
2
3
  fstream fio;
  Hardware ht;
  init(ht, fio);


The initializing function begins to fill this temporary class, HT, and write it to FIO in a spot determined by the temporary class's item ID.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void init(Hardware ht, fstream& fio) 
{
fstream fio("hardware.dat", ios::in | ios::out | ios::binary | ios::trunc);
int id, or ; 
float ma, se;
char name[30];
fstream init("init.txt", ios::in);
while (!init.eof())
	{
		init >> id >> or >> ma >> se; init.getline(name, 20);
		ht.init(id, or , ma, se, name);
		fio.seekp(id);
		fio.write((char*)(&ht), sizeof(ht));
	}


Now, this seems to work fine. It seems to be writing properly. The problem comes from trying to open this in a later function to READ from. The information is flat out unreadable.

This is how the function is called in the main.
 
check(ht,fio);


And this is the bulk of the function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void check(Hardware ht, fstream& fio)
{
	fio.open("hardware.dat");
	if (!fio)
	{
		cout << "Can't open file";
		_getch();
		exit(1);
	}

	int in, i;
	cout << "Enter an item ID. " << endl;
	cin >> in;
	for (i = 0; i < 200; i++)
	{ 
		fio.seekg(i);
		fio.read((char*)(&ht), sizeof(ht));
		if (ht.getID() == in)
		{
			ht.print();
		}
	}


What is it about my syntax with opening the file that makes it incomprehensible? The read temporary class is filled with who knows what after each run of the for loop.

In short, the binary file that is written to becomes unusable, and I don't know why.
You haven't shown the definition of type Hardware, so I have no idea what you're trying to read or write.

init line 12: You're doing a seekp based on the value of id. seekp positions based on the byte position of the argument. Are your ids really byte positions? There is really no need to do a seekp here. Just write your records sequentially.
http://www.cplusplus.com/reference/ostream/ostream/seekp/

check line 3: You're opening the file in text mode.

check line 14: Your for loop assumes there are exactly 200 entries in the file. Not a good assumption.

check line 16: Again, you're doing a seek based on the byte position of an arbitrary number (i). First time through is fine since you will seek to 0. The second time through the loop, you will position to the second byte in the file (i=1), even though you were correctly positioned after the first read. No need for the seek here either.

check line 17: You don't check the result of the read. You simply continue assuming it worked.
Last edited on
I do see what you're saying. The data file is designed to have 200 record entries that are empty, initialized off screen, which i have done fine. So an item with an id of 3 will be put into record 3, etc. That is why seekp is used to put the records in their corresponding ID locations.

This is the class definition:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Hardware {
private:
	int itemID;
	int pOrdered;
	int pInStore;
	float manufPrice;
	float sellingPrice;
	int pSold;
	char itemName[30];
public:
	Hardware();
	int getID();
	int getStock();
	void print();
	void sale();
	void order();
	void rec();
	void init(int id, int or , float ma, float se, string name);
};

void Hardware::init(int id, int or , float ma, float se, string name)
{
	itemID = id;
	pOrdered = or ;
	manufPrice = ma;
	sellingPrice = se;
	strcpy_s(itemName, "");
}
So an item with an id of 3 will be put into record 3, etc. That is why seekp is used to put the records in their corresponding ID locations.

If you want to position based on id, then you need to multiply id * sizeof(Hardware). Streams are byte oriented. They have no concept of records.
1
2
3
  fio.seekp (id * sizeof(Hardware));  // calculate byte position of record
...
  fio.seekg (i * sizeof(Hardware));


Note: In Hardware::init (line 27), you're initializing itemName to blanks, not the name that was passed.



Yeah, itemName strcpy_s was giving me trouble so I just initialized it to something blank to take care of other problems. This solved it though, thank you!
Topic archived. No new replies allowed.