Reading from a binary file.

Aug 1, 2011 at 7:55pm
Hello all

I'm trying to read information from a binary file (employees.bin), into a struct. However, I'm unsure on why my data is not being read correctly.

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <conio.h> // for "getch()"
using namespace std;
const int MAX = 100;



struct empdata
{
    //data members
        char firstname[13];
	char lastname[13];
	char idnumber[12];
	char datehired[9];
        double payrate ;
	double hoursworked ;
	double grosspay;
};




int main ()
{
        empdata EmployeeRecord;
	int index = 0 , limit = 0;



	fstream labfile;
	labfile.open("testEmployees.bin", ios::in | ios::binary);



	if(labfile.fail())
	{
		cout << "Unable to open the data file!!!" <<endl;
		cout << "Please make sure your bin file is in the same location as the program!"<<endl<<endl<<endl;
		system("PAUSE");
		return 999;

	}

        labfile.seekg(0,std::ios::beg);
	labfile.read(reinterpret_cast<char*>(&EmployeeRecord), sizeof(EmployeeRecord));


	while(!labfile.eof())
	{
**Here im just testing to see if the correct data went in.
        cout<<EmployeeRecord.firstname<< endl;
	    cout<<EmployeeRecord.lastname<< endl;
	    cout<<EmployeeRecord.idnumber<< endl;
	    cout<<EmployeeRecord.datehired<< endl;
	    cout<<EmployeeRecord.payrate<< endl;
	    cout<<EmployeeRecord.hoursworked<< endl;

	    labfile.read(reinterpret_cast<char*>(&EmployeeRecord), sizeof(EmployeeRecord));
	    getch();
	}

    labfile.close();
	getch();
	return(0);
}

And i get:
Andrew
Conyers
219-52-2044
02231988
3.43597e+010<<<<wrong, should be payrate
1.72632e-306<<<<wrong, should be hours worked


The payrate and hoursworked are wrong when reading the first record.
Once I hit enter so that it reads the file for the next record, all of the values are off.

Been looking for an answer for a while and haven't been able to find it.

Any help is appreciated. Thanks in advance.
Aug 1, 2011 at 8:31pm
this is the format of scientific !!! i dont know what you write in your file and then what you read from of but test it in begining of your code :

cout.setf(ios::fixed, ios::floatfield);
Aug 1, 2011 at 10:14pm
tested it, now I get

34359746702.000000<<payrate
0.000000<<hours worked

BTW, I'm not writing anything to a file, just reading. He asks me to make a struct with the data members: first, last, ID, date hired ,pay and hours.

Then declare a single object variable named EmployeeRecord and write a loop control structure to read data from a .bin file my professor made, one record at a time, into the employeerecord variable.

Does it have anything to do with atof or null terminator?

Also is there anything I can read to help, went over the chapter twice but it only explains how to do it the basic way.
Aug 1, 2011 at 11:52pm
I'm not sure if I fully understand what you're trying to do here but I would recommend that rather than trying to read the whole struct in one go you should try to take each piece. So if your struct was something like:
1
2
3
4
5
6
7
8
9
10
11
struct MyStruct
{
  int i;
  char c;
}

//read each piece individually like this
int readNumber = 0;
char readChar = '';
labfile.read( &readNumber, sizeof(int) );
labfile.read( &readChar, sizeof(char) );


maybe I'm missing the point here... hope it helps!
Aug 2, 2011 at 12:16am
Were you given the struct definition? Sizes and all?
Aug 2, 2011 at 12:28am
For your struct def

1
2
3
4
5
6
7
8
9
10
int main()
{
	size_t a = sizeof(empdata);
	size_t b = sizeof(char) * (13 + 13 + 12 + 9) + sizeof(double) * 3;

	std::cout << a << std::endl;
	std::cout << b << std::endl;

	return 0;
}


produces the following output

72
71


Assuming you haven't overridden the compilers default packing?

So you are reading one additional byte cf. the members declared in struct.
Aug 2, 2011 at 12:39am
@ceruleus
These worked one by one for the chars in the struct, but I'm still not getting the right info for the doubles...
'
1
2
3
4
5
6
7
8
9
10
	
    labfile.read(reinterpret_cast<char*>(&EmployeeRecord.firstname), sizeof(EmployeeRecord.firstname));
    labfile.read(reinterpret_cast<char*>(&EmployeeRecord.lastname), sizeof(EmployeeRecord.lastname));
    labfile.read(reinterpret_cast<char*>(&EmployeeRecord.idnumber), sizeof(EmployeeRecord.idnumber));
    labfile.read(reinterpret_cast<char*>(&EmployeeRecord.datehired), sizeof(EmployeeRecord.datehired));


This didnt work
   labfile.read(reinterpret_cast<char*>(&EmployeeRecord.payrate), sizeof(EmployeeRecord.payrate));
    labfile.read(reinterpret_cast<char*>(&EmployeeRecord.hoursworked), sizeof(EmployeeRecord.hoursworked));


Still getting weird info for payrate and hoursworked(looks like 3.43597e+010), when it should return in values of payrate(999.99) and hoursworked(99.9)

..............

@andy this is the info he gave us, along with a pdf file that says what he wants us to do in the assignment and a bin file(testemployees.bin).

He said-
"For you information, in case you need it, I used the following character counts for the char array string values in the structure used to create the binary data file. It should not matter, but I want you to have the details just in case."
first name and last name: 12+1 (13) <-- that means a maximum of 12 characters + 1 for the NULL
id: 11+1 (12)
date hired: 8+1 (9)
pay rate: float
hours worked: float


And the pdf. file with the assignment says:

"Use the structure definition from lab 4(that's the struct I'm using) that represents the employee data type. Declare a Single object variable and name it employeerecord. Write a looping control structure to read data, one record at a time, into this employeerecord variable. NOTE: The data file I created is a binary data file(testemployees.bin)."

The assignment asks me to do other stuff after that but I can't even get the data to read properly into the struct. Been trying to find a solution for days now but I can't figure it out. If not then i'll just have to wait until after a test tomorrow to ask him about it, but i'm a bit worried about something like this showing up on the test.
Last edited on Aug 2, 2011 at 1:32am
Aug 2, 2011 at 7:58am
@Technyque (8):
labfile.read(reinterpret_cast<char*>(&EmployeeRecord.firstname), sizeof(EmployeeRecord.firstname));

this code not right because firstname is the address of first block which array be started !! then you can wrote
reinterpret_cast<char*>(EmployeeRecord.firstname)
or
reinterpret_cast<char*>(&EmployeeRecord.firstname[0])
i dont know but i read in complete reference STL , reinterpret_cast is not good idea then you just write
(char *)&obj is better ! but i dont know why !!
your first code dont have any problem just are you sure about your file ?!!! if you dont know about inside of them , then how do you know its true ?!!!

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
you can test yourself just debug this code and see yourself :

struct empdata
{
	//data members
	char firstname[13];
	char lastname[13];
	char idnumber[12];
	char datehired[9];
	double payrate ;
	double hoursworked ;
	double grosspay;

	empdata()
	{
		strcpy(firstname, "asdf");
		strcpy(lastname, "fdfdf");
		strcpy(idnumber, "");
		strcpy(datehired, "aaaaa");

		payrate = 123;
		hoursworked = 111;
		grosspay = 0;
	}
};

void main()
{
	empdata e;

	empdata rr; // just for check!!

	// just for check !!!! 
	rr.grosspay = 111111;
	rr.hoursworked = 0;
	strcpy(rr.firstname, "");

	ofstream fout("a.dat", ios::out | ios::binary);
	fout.write((const char *)&e, sizeof( empdata ));
	fout.close();

	ifstream fin("a.dat", ios::in | ios::binary);
	fin.read((char *)&rr, sizeof( empdata ));
	fin.close();
}
Last edited on Aug 2, 2011 at 8:09am
Aug 2, 2011 at 3:00pm
@OP you said that this doesn't work:

1
2
labfile.read(reinterpret_cast<char*>(&EmployeeRecord.payrate), sizeof(EmployeeRecord.payrate));
    labfile.read(reinterpret_cast<char*>(&EmployeeRecord.hoursworked), sizeof(EmployeeRecord.hoursworked));


That makes sense since you are casting a double to a char, so of course it won't work. When using basic types (like double, int, char, etc...) you should just use a c-style cast:

1
2
labfile.read( (double)&EmployeeRecord.payrate, sizeof( double ) );
    labfile.read( (double)&EmployeeRecord.hoursworked, sizeof( double ) );


edit: also, I edited the above... I'm not sure if your second parameter to read is valid, use sizeof(type) instead
Last edited on Aug 2, 2011 at 3:00pm
Aug 2, 2011 at 3:23pm
@ahura24


Bingo! I ran your code to create "a.dat", and using my original code it's reading all the data from "a.dat" like it's supposed to. I guess this means the .bin file that my prof gave us may need to be fixed?

Thanks for all the help, will mark as solved later today after I talk to him.

Aug 2, 2011 at 3:39pm
I would be interested to here what your prof's solution is.

For binary data it is standard practice to write or read a single record (= structure) at a time, as you were attempting to do earlier on.
Last edited on Aug 2, 2011 at 6:49pm
Aug 2, 2011 at 6:23pm
would this be by single record? I'm pretty sure he wanted it read like this but i guess ill see.

labfile.read(reinterpret_cast<char*>(&EmployeeRecord), sizeof(EmployeeRecord));

@ceruleus,
I get: invalid cast from type 'double*' to type 'double', when it try it that way.

I'm thinking it may be something wrong with the .bin file he provided us with, I'll let ya'll know what he says.
Last edited on Aug 2, 2011 at 6:35pm
Aug 2, 2011 at 7:27pm
@Technyque then change the (double)&EmployeeRecord.payrate to (double*)&EmployeeRecord.payrate

The point I was trying to get across is that I think you don't need to use reinterpret_cast or any of those fancy object casts. You should probably just be using a c-style cast like the above code. I'm really not sure though can someone step in and correct me/agree with me here?
Last edited on Aug 2, 2011 at 7:27pm
Aug 2, 2011 at 7:41pm
I am a bit concerned about the comment about c-style versus reinterpret cast

I have just checked Sutter and Alexandrescu (C++ Coding Standard) and it states "Don't use C-style casts".

Ever!
Aug 2, 2011 at 10:44pm
Just talked to someone in my class. Never felt like such a noob in my life lol...

The .bin file good, I was supposed to use float instead of double in my struct. Don't know how I missed that, I even posted the email he sent our class with the directions, which states that those 2 values were float.

Thanks everyone that tried to help and sorry for wasting your time.
Aug 4, 2011 at 12:24am
:-)

The advantage of mistakes is that they help to "burn" facts into your mind!
Last edited on Aug 4, 2011 at 12:24am
Topic archived. No new replies allowed.