Writing then reading binary files.

Hi all. I have been set a task for my c++ class. I have to create a program to take input about a companys weekly timesheets (Employee ID, hours worked, hourly rate, that sort of thing). I am then to write this information to a binary file which can then be read. The aim is to create payslips from some of the data while having the original binary as a backup.

My problem comes from reading the binary file back and displaying it. When I try to display it I get the first few records but then the output is incorrect and the console crashes. Any input on my problem would be much appreciated.
(Im running code::blocks on windows XP)

Here is my code:

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

struct times{
	int empID;
	char lastName[15];
	char firstName[15];
	int dept;
	float hours;
	float overTime;
	float rate;
	string date;
};

times timesheet[20];
void Display();
void readFileByRecord();
void getTimeData();
void displayTimeData();
void writeBinary();
string sheetDate;
string filename;
int rows;
int y;

int main()
{
getTimeData(); //get user input
displayTimeData(); //display the users input
writeBinary(); //write input to binary file
readFileByRecord(); //read binary file
Display(); //display whatever the binary file contained
}

void getTimeData()
{
    cout << "Enter the end of week date (dd.mm.yy: include the full stops)" << endl;
    cout << "This will be used for all data on this timesheet" << endl;
    cin >> sheetDate;

    for (int i = 0; i <= 2; i++){
        timesheet[i].date = sheetDate;
    cout << "Enter employee ID: " << endl;
	cin >> timesheet[i].empID;
	cout << "Enter last name: " << endl;
	cin >> timesheet[i].lastName;
	cout << "Enter first name: " << endl;
	cin >> timesheet[i].firstName;
	cout << "Enter department no.: " << endl;
	cin >> timesheet[i].dept;
	cout << "Enter hours worked: " << endl;
	cin >> timesheet[i].hours;
            if (timesheet[i].hours > 37.5)
        {
            cout << "Enter overtime worked: " << endl;
            cin >> timesheet[i].overTime;
        }
            else
        {
            timesheet[i].overTime = 0;
        }
	cout << "Enter hourly rate: " << endl;
	cin >> timesheet[i].rate;
}
}

void displayTimeData()
{
    for(int x = 0; x <= 2; x++){
    cout << timesheet[x].empID << endl;
    cout << timesheet[x].lastName << endl;
    cout << timesheet[x].firstName << endl;
    cout << timesheet[x].dept << endl;
    cout << timesheet[x].hours << endl;
        if (timesheet[x].overTime != 0)
        {
            cout << timesheet[x].overTime << endl;
        }
    cout << timesheet[x].rate << endl;
    cout << timesheet[x].date << endl;
    }
}

void writeBinary()
{
filename = sheetDate + ".bin";
ofstream outFile(filename.c_str(),ios::binary);
outFile.write((char*)timesheet, sizeof(timesheet));
outFile.close();
}

void readFileByRecord()
{
	rows=0;
	ifstream myfile(filename.c_str(),ios::binary);
	if (!myfile.is_open())
		cout << "Unable to open file: " << filename.c_str() << endl;
	else
	{
		while ( !myfile.eof() )
		{
			myfile.read((char *)&timesheet[rows], sizeof(times));
			rows++;
		}
		myfile.close();
		rows--;
	}
}


void Display()
{
	for ( y=0;y<rows;y++ )
		cout << timesheet[y].empID << " " << timesheet[y].lastName
        << " " << timesheet[y].firstName << " " << timesheet[y].dept << " " << 
        timesheet[y].hours << " ";
        		if (timesheet[y].overTime != 0)
					{
					    cout << timesheet[y].overTime << " ";
					}
        cout << timesheet[y].rate << " " << timesheet[y].date << endl;
}


Some example output (dont ask where I come up with the names, I just hit keys :P)

12 Bobby Bob 4 12 15 Lendon Blik 4 75 12 Grando Polto 14 15 0  0 0 0  0 0 0
  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0 
  0 0 0  0 0 0  0 0 0  0 0 0  0 0 0  0 0 8.40779e-045 0



Thanks for your time!
What do you mean by "binary file". Can you post your exact assignment?

I ask, because this kind of CSV data is usually stored textually. If you want to keep it in a non-textual database, some additional structure must be applied, which typically splits things up.

If you are interested in serialization of an object containing both textual and non-textual data into a non-textual file, that again requires a little bit of extra work and structure. (Well, maybe not so much "extra work" as "different" work.)
You can only do that if you're dealing with Plain Old Data types.
http://www2.research.att.com/~bs/C++0xFAQ.html#PODs

Because times has a string, it's not a POD type.

What's acutally happening is the string in times is an object that has pointers to dynamically allocated memory. These are maintained by the object (constructor/destructor/copy and so on) and so you can't simply bit-blit the thing as you end up changing those pointer values, making the internal state of the string invalid.

To fix it, change the date field to a char array as you've done for the name fields.
Last edited on
Hi guys, sorry for late response, my friend 'forced' me to get drunk yesterday.

I have changed the string in times to a char. I am having a problem now trying to use the char date inside my struct to apply to all of the timesheet[i].date. Here is my changed code:

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
struct times{
	int empID;
	char lastName[15];
	char firstName[15];
	int dept;
	float hours;
	float overTime;
	float rate;
	char date; //changed to char
};

times timesheet[20];
void Display();
void readFileIntoArrayByRecord();
void getTimeData();
void displayTimeData();
void writeBinary();
string sheetDate;
string filename;
int rows;
int y;
const char *SDate; //added to convert the string sheetDate (which I use to name the output file)
//to a char to add into my struct
int main()
{
getTimeData();
displayTimeData();
writeBinary();
readFileIntoArrayByRecord();
Display();
}

void getTimeData()
{
    cout << "Enter the end of week date (dd.mm.yy: include the full stops)" << endl;
    cout << "This will be used for all data on this timesheet" << endl;
    cin >> sheetDate;
SDate = sheetDate.c_str(); //string to char conversion

    for (int i = 0; i <= 2; i++){
                timesheet[i].date = SDate; //problem is here
    cout << "Enter employee ID: " << endl;


I'm not exactly sure how to fix it, any input would be appreciated. Thanks!
Just glancing at your code:

1. Bug on Line 40 - date is only one char, as declared on Line 9.
2. Bug on Line 91 of your original file - you are only writing out one record.

BTW, this is actually a very good exercise, so learn to do it well. Learn to do it correctly.

Binary files are extremely useful - I use them to read/write out gigabyte-size files in milliseconds that would actually take minutes using their equivalent ASCII.
Last edited on
2. Bug on Line 91 of your original file - you are only writing out one record.
outFile.write((char*)timesheet, sizeof(timesheet)); timesheet is an array, it is writing all the array
Topic archived. No new replies allowed.