0

I'm reading blocks of data from the file, but not all at once (ex. 3 bytes per read/write) and then write same 3 bytes back to file to the very same position inside a file, and then continue looping until there are no more blocks to read.

In other words I'm trying to rewrite the file by it's very contents.

However there is a problem that final output isn't the same as it was in the beginning.

Following sample code reads 3 bytes per iteration from a file "sample.txt", file contents are simple:

0123456789

after reading data and writing data back to file, the contents are:

012345345345

As you see data doesn't get rewritten correctly for some reason.

#include <fstream> #include <iostream> using namespace std; #define BLOCK_SIZE 3 int main() { // open file fstream file; file.open("sample.txt", ios::binary | ios::out | ios::in); // determine size and number of blocks to read file.seekg(0, ios::end); streampos size = file.tellg(); int blocks = size / BLOCK_SIZE; cout << "size:\t" << size << endl; if (size % BLOCK_SIZE != 0) { ++blocks; } cout << "blocks:\t" << blocks << endl; // return to beginning file.seekg(ios::beg); // we will read data here unsigned char* data = new unsigned char[BLOCK_SIZE]; streampos pos; // read blocks of data and write data back for (int i = 0; i < blocks; ++i) { pos = file.tellg(); cout << "before read:\t" << pos << endl; // read block file.read(reinterpret_cast<char*>(data), BLOCK_SIZE); cout << "after read:\t" << file.tellg() << endl; // write same block back to same position file.seekp(pos); cout << "before write:\t" << file.tellg() << endl; file.write(reinterpret_cast<char*>(data), BLOCK_SIZE); cout << "after write:\t" << file.tellg() << endl; // reset buffer memset(data, 0, BLOCK_SIZE); } file.close(); delete[] data; cin.get(); return 0; } 

Do you see what could be the reason for bad overwrite?

EDIT: Sorry, I can't see how the linked duplicate answers my question, I'm simply unable to apply given answer to the code above.

11
  • This works for me. You do have a problem in that you do not handle the end-of-file condition very well. Commented Apr 9, 2019 at 18:19
  • How it works for you? Can you give the code that works? Commented Apr 9, 2019 at 18:26
  • I ran the exact code you have there. Commented Apr 9, 2019 at 18:32
  • hm, what is the problem then, why file doesn't get properly rewritten here on my machine? I don't see anything implementation defined? the code should run equivalently on all machines right? Commented Apr 9, 2019 at 18:36
  • 1
    You just need to do a seekg before reading as stated in the duplicate, works for me in visual studio Commented Apr 10, 2019 at 5:29

1 Answer 1

0

Your code does not handle the EOF condition well, and leaves the stream in a bad state after trying to read past the end of the file. On my system, this results in all further calls to the stream having no effect. I bet that isn't the case on your system (which I suspect is a bug in its iostream implementation). I re-did your code to handle the EOF condition correctly, and also to be a lot cleaner in a few other ways:

#include <fstream> #include <iostream> using namespace std; const int BLOCK_SIZE = 3; int main() { // open file fstream file; file.open("sample.txt", ios::binary | ios::out | ios::in); // we will read data here bool found_eof = false; // read blocks of data and write data back while (!found_eof) { unsigned char data[BLOCK_SIZE] = {0}; char * const data_as_char = reinterpret_cast<char *>(data); streampos const pos = file.tellp(); int count_to_write = BLOCK_SIZE; cout << "before read:\t" << file.tellg() << ' ' << pos << '\n'; // read block if (!file.read(data_as_char, BLOCK_SIZE)) { found_eof = true; count_to_write = file.gcount(); file.clear(); cout << "Only " << count_to_write << " characters extracted.\n"; } cout << "after read:\t" << file.tellg() << ' ' << file.tellp() << '\n'; // write same block back to same position file.seekp(pos); cout << "before write:\t" << file.tellg() << ' ' << file.tellp() << '\n'; file.write(data_as_char, count_to_write); cout << "after write:\t" << file.tellg() << ' ' << file.tellp() << '\n'; file.seekp(file.tellp()); } file.close(); cin.get(); return 0; } 

But, this is not fundamentally different. Both versions work for me just the same. I'm on Linux with g++.

From the linked to possible dupe, I would also suggest adding this just before the closing } of your for loop:

file.seekp(file.tellp()); 

I've put that in my code in the appropriate place.

Sign up to request clarification or add additional context in comments.

4 Comments

I copied your code and it results in infinite loop.
@zebanovich - It works fine on my system. It sounds like you might have a buggy iostream implementation. Which compiler and which platform?
This is really puzzling, Windows 10 x64, msvc-v142 (VS 2019 Preview)
why casting - reinterpret_cast<char > required ? VS2019 suggesting to use just (char)