Hello,

I've got the following code:

wxString path = filepath;
	wxString newpath = filepath;
	fstream f(path.Append("/tests/tests.bin"), ios::in | ios::binary);
	fstream fnew(newpath.Append("/tests/temp.bin"), ios::out | ios::binary);

	Test* transferTest = new Test();

	int thisSize = sizeof(Test);

	bool success = false;

	bool toBeDeleted = false;

	int testNo = 1;

	if (f)
	{
		f.seekg(0, ios::beg);
		fnew.seekp(0, ios::beg);
		while (testNo <= noOfTests)
		{

			toBeDeleted = false;
			for (int i = 0; i < noOfSelectedRows; i++)
			{
				int row = selectedRows[i];

				if (testNo == row)
				{
					toBeDeleted = true;
				}
			}
			if (!toBeDeleted)
			{

				f.read(reinterpret_cast<char *>(transferTest), thisSize);
				fnew.write(reinterpret_cast<char *>(transferTest), thisSize);
				fnew.seekp(testNo*thisSize, ios::beg);
			}
			f.seekg(testNo*thisSize, ios::beg);
			testNo++;

		}

		success = true;

		f.close();
		fnew.close();

		remove(path.c_str());

		rename(newpath.c_str(), path.c_str());
	}

	delete transferTest;

Essentially, what I have is a binary file with objects of the class Test. Trough a list in my GUI I make it possible to delete objects from this bunch. And it works fine as long as I delete one or more objects at the end of the file. However if I try to delete an object in the middle of the bunch, there becomes a "hole" in the "temp.bin" file and it keeps on writing the rest of the objects perfectly fine. So the file gets the exact same size as before.

I've been staring at this for a while now and I really can't see why it doesn't work the way I want it to, so hopefully someone can help :)

Thanks in advance!

Recommended Answers

All 2 Replies

At a glance I'd say it's because you're seeking when you don't need to seek, and your position calculations are incorrect. Let's review:

>f.seekg(0, ios::beg);
>fnew.seekp(0, ios::beg);
You just opened these files, they're already at the beginning.

>fnew.write(reinterpret_cast<char *>(transferTest), thisSize);
>fnew.seekp(testNo*thisSize, ios::beg);
When you write to an output stream, it updates the put pointer automatically. If testNo*thisSize doesn't equal what the pointer is at currently every single time (which brings up the question of redundancy and why you're even bothering with seekp), you're looking at either holes in the file or corrupted data.

Here's a more intuitive solution:

ifstream in ( "input", ios::binary );
ofstream out ( "output", ios::binary );

if ( in && out ) {
  int testNo = 0;
  Test record;

  while ( in.read ( (char*)&record, sizeof record ) ) {
    if ( !pending_delete ( ++testNo ) )
      out.write ( (char*)&record, sizeof record );
  }

  in.close();
  out.close();
}

pending_delete would, of course, be a wrapper for the current hard coded loop you have:

bool pending_delete ( int row )
{
  for (int i = 0; i < noOfSelectedRows; i++) {
    if (row == selectedRows[i])
      return true;
  }

  return false;
}

On a side note, unless your Test class is a POD type, using direct I/O is unsafe. A better all around solution would be to support either overloaded << and >> operators for stream I/O, or a to_string member function for serializing object of Test into a string.

Thanks mate, I went with the "more intuitive" solution and it worked like a breeze. I'll consider the side not if I have time :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.