3

I have some internal file which can only be appended to and after each appending \n character is added to the file. But theoretically it is possible that appending to the file is failed and it becomes corrupted. That is why every time when opening the file I want to seek to its last valid, after last EOL, position. This code will do that:

// Not using ios::app instead of ios::ate | ios::out because it will
// put print pointer to the EOF every time before writing.
fstream file(name.c_str(), ios::binary | ios::ate | ios::out | ios::in);
if(!file.is_open()) {
    cerr << "Error in oppening file " << name << endl;
    exit(EXIT_FAILURE);
} else {
    while(0 != file.tellp()) //if file is not empty
    {
        file.seekg(-1, ios_base::cur);
        if(0 == file.tellg() || file.get() == '\n') {
            break;
        }
        file.seekg(-1, ios_base::cur);
    }
    file.seekp(of.tellg());
}
//{1}
//Use file for appending to...

But it wouldn't work fine if the length of part which should be appended to the file is lower than the length of part starting from the last EOL character in the file. That is why in {1} position I want to delete file content starting from file.tellp() to the end.

How can I do that?

Mihran Hovsepyan
  • 10,810
  • 14
  • 61
  • 111

2 Answers2

1

There is no portable way to do this (see James Kanze much better answer for a fuller explanation).

If you are on a POSIX system, then you can use ftruncate (see here) to set the length of a file to a certain length. I do not know of a C++ equivalent (see this question for more information)

Community
  • 1
  • 1
Jeff Foster
  • 43,770
  • 11
  • 86
  • 103
  • `ftruncate` is Unix only. And it doesn't take a stream or a `FILE*` as argument either. – James Kanze Apr 20 '12 at 10:11
  • It's not ideal (as I said, I don't know of a C++ one). I didn't realize it was a POSIX only command. On Windows, it looks like you need to use `_chsize_s` to achieve the same thing. – Jeff Foster Apr 20 '12 at 10:13
  • Under Windows, the corresponding function would be `SetEndOfFile`. Both require the system handle to work (and not a `filebuf` nor a `FILE*`, so neither are C++, nor C). – James Kanze Apr 20 '12 at 10:33
  • OK, thanks for clarifying this. I'll edit the answer to reflect the non-portability. – Jeff Foster Apr 20 '12 at 10:43
1

You can't, portably. Different systems have different ways of doing this, but typically only on a system file handle. The only guaranteed way of shortening a file is to copy it into another file, not copying what you don't want, then delete the original and rename the new file.

If it's a text file (not binary), and you are under windows, writing a 0x1A at the position might work. There's nothing similar under Unix, however.

In your case, wouldn't just overwriting the end be enough. If worse comes to worse, and what you need to append isn't sufficient to overwrite the trailing data, you might try overwriting it with something inoculous and easily recognizable, like '\0'. (Formally, writing things like this, or the 0x1A, to a text file is undefined behavior. Practically, it will work.)

(When I had to solve a similar problem, I adopted the policy of writing a CRC of the block at the head of the record; on reading, I ignored anything for which the CRC was wrong.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329