Fstream binary question

I can't figure out how to add 5 to every byte, and not just the last value in the Loan object.

Loan Objects: that were written to the binary i/o file
1
2
3
4
5
6
// Instantiate loan objects
	Loan loan1(5.3, 10, 20000);
	Loan loan2(3.0, 5, 10000);
	Loan loan3(10.9, 7, 15000);
	Loan loan4(21.3, 5, 10000);
	Loan loan5(2.3, 3, 5000);


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
// Read array from the file
	fstream binaryio; // Create stream object

	// Read loan back from the file
	binaryio.open(inputFilename, ios::in | ios::binary);

	binaryio.seekg (0, ios::end);
	int length = binaryio.tellg() / sizeof(int);
	binaryio.seekg(0); //to return the file pointer to the beginning
	Loan *newLoan = new Loan [length];

	Loan *result;
	result = new Loan [length];

	// Display array
	for (int i = 0; i < length; i++)
	{
		// Reading one int at a time
		binaryio.read(reinterpret_cast<char*> (&newLoan[i]), sizeof(newLoan[i]));
		if ( binaryio.eof() ) // Will check for end of file
			 break; // Exit from the while if end of file
		displayLoan(newLoan[i]);
		// Add 5 to every byte
		result[i] = newLoan[i] + 5;
		displayLoan(result[i]);
		// Then I will write result to another file
	}


Output:
Enter an input file name: C:\Users\KraigBalla\Documents\Visual Studio 2010\Projects\Homework\13.6\Exercise13_6.dat
5.3 10 20000
5.3 10 20005
3 5 10000
3 5 10005
10.9 7 15000
10.9 7 15005
21.3 5 10000
21.3 5 10005
2.3 3 5000
2.3 3 5005
Press any key to continue . . .

You can see that it only adds 5 to the last value in the Loan object. I want 5 to be added to every byte...any ideas?
Well, you have not disclosed the structure of the Loan class. I am assuming it to be the following:

1
2
3
4
5
6
7
class Loan
{
	public:
	double element1;
	int element2;
	int element3;
};


If so, you should not say that you want to add 5 to every byte of the object. Instead you write, you want to add 5 to every element of the object. Further the compiler will generate an error in line 24 of your posted code. The error would look like the following when using g++ compiler:


no match for ‘operator+’ in ‘*(((Loan*)(((unsigned int)i) * 16u)) + newLoan) + 5’


To solve this, you have to define the + operator for the Loan class. Check the following 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
class Loan
{
	public:
	double element1;
	int element2;
	int element3;

	public:
	Loan operator+ (int n) const;
};

Loan Loan::operator+ (int n) const
{
	Loan addedLoan (*this);
	addedLoan.element1 += n;
	addedLoan.element2 += n;
	addedLoan.element3 += n;
	return addedLoan;
}

int main (void)
{
	int length;

	/**** Determine length ****/

	Loan *newLoan = new Loan [length];
	Loan *result = new Loan [length];

	/**** Fill the newLoan array ****/

	for (int i = 0; i < length; i++)
		/**** It fills result[i] after adding 5
		to all the elements of newLoan[i]. ****/
		result[i] = newLoan[i] + 5;
}


Further some words of caution. When writing to binary files, do not write/read the object directly using write/read function. This is dangerous if the class has virtual methods. Further if the file format is given by a third party vendor, the size of each entry is predefined. Try the following example. Suppose the requirement is, each entry in the binary file is a pair of a char (1 byte) and a float (4 bytes), i.e. 5 bytes all together. You would be tempted to declare a class with two variables.

1
2
3
4
5
class Record
{
	char c;
	float f;
};


And write the objects of this class directly to the binary file. Just for fun, do cout << sizeof (Record) << endl; to see its size. Is it 5?
That works like a charm. Thanks

Here's what I put for my overloaded operators:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

// For encrypting
Loan Loan::operator+(const int num) const
{
	// This refers to object that uses operand
    Loan tmp = *this;
    // Then add to the val 5
    tmp.loanAmount += num;
	tmp.numberOfYears += num;
	tmp.annualInterestRate += num;
    return tmp;
}

// For decrypting
Loan Loan::operator-(const int num) const
{
    Loan tmp = *this;
    //then add to the val you want
    tmp.loanAmount -= num;
	tmp.numberOfYears -= num;
	tmp.annualInterestRate -= num;
    return tmp;
}
I have a for loop that does this:

1
2
3
4
5
6
7
8
9
10
11
for (int i = 0; i < length; i++)
	{
		binaryio.open("test11.bak", ios::out | ios::binary);
		binaryio.write(reinterpret_cast<char*>(&result[i]), sizeof(result[i]));
		if (result[i] == '\0') // Testing end of array
		{
			// If end of array
			break;
		}

	}


How can I create an operator to handle the "=="?
Since your i is less then length, you should stay inside the result array at all times. You can not get past the end, because the index is within bounds. Or do I understand your question incorrectly?

Regards
Length is the size of the previous read file...after reading the first file I am trying to encrypt and write back to a different file. So the length could be larger than the last index of the array. So I'm trying to add a break in the loop if the last index of the array as been written.
So, the encryption changes the size of the information. How do you know that the buffer will not overflow then, when the encrypted content is written to it? In all cases, you have to know the size of the encrypted content in advance somehow. If we are talking the case where some value is added to every field, this does not change the size of the array.

Regards
I condensed t down to one for loop...This loop will read, write (encryption of 5 to every index), and then read again. Everything is working but the third read is displaying the wrong numbers. Any ideas?

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
        binaryio.open(inputFilename, ios::in | ios::binary);
	bi.open("test11.bak", ios::out | ios::binary);
	b.open("test11.bak", ios::in | ios::binary);

        Loan *newLoan = new Loan [length];
	Loan *result = new Loan [length];
	Loan *newLoan1 = new Loan [length];

	// Display array
	for (int i = 0; i < length; i++)
	{
		// Reading one int at a time
		binaryio.read(reinterpret_cast<char*> (&newLoan[i]), sizeof(newLoan[i]));
		if ( binaryio.eof() ) // Will check for end of file
			 break; // Exit from the while if end of file
		displayLoan(newLoan[i]);
		// Add 5 to every byte
		result[i] = newLoan[i] + 5;
		displayLoan(result[i]);
		// Then I will write result to another file
		bi.write(reinterpret_cast<char*>(&result[i]), sizeof(result[i]));

		// Reading this
		b.read(reinterpret_cast<char*> (&newLoan1[i]), sizeof(newLoan1[i]));
		displayLoan(newLoan1[i]);
	}
Last edited on
One approach is to use flush:
1
2
3
4
5
6
		// Then I will write result to another file
		bi.write(reinterpret_cast<char*>(&result[i]), sizeof(result[i]));
                bi.flush();

		// Reading this
		b.read(reinterpret_cast<char*> (&newLoan1[i]), sizeof(newLoan1[i]));

Alternatively, doing the following will ensure that flush is called before every read automatically:
1
2
3
4
5
        binaryio.open(inputFilename, ios::in | ios::binary);
	bi.open("test11.bak", ios::out | ios::binary);
	b.open("test11.bak", ios::in | ios::binary);
        b.tie(&bi);
        ...

http://www.cplusplus.com/reference/iostream/ios/tie/

Regards
Topic archived. No new replies allowed.