tags:

views:

125

answers:

3

I need to open a file as ofstream and write to the front of the file, while preserving the remaining contents of the file, which will be "moved". Similar to "prepend" a file.

Is this possible using the STL or boost ?

+4  A: 

No it isn't. And this has been asked here many times before. If you want to do this you have to create new file, write the "prepend" data to it, then open the existing file and copy its contents to the new file.

anon
+12  A: 

No -- the language (or library) doesn't really make much difference here. Most file systems just don't allow it, full stop.

The usual way to get the same effect is to write your new data to a new file, then copy the data in the old file to the new file following the data you wrote.

Jerry Coffin
How can you say it's impossible and then describe how to do it? Boost provides a portable filesystem library http://www.boost.org/doc/libs/1_42_0/libs/filesystem/doc/index.htm with `boost::remove` which does in fact make a difference if you want to unlink the old file and make a new file — not that such is essential, or even a good way of implementing it. OP didn't ask for a one-liner, he asked for help.
Potatoswatter
He doesn’t describe how to do it; he describes the standard workaround for this problem.
Nate
Uh, being a workaround would imply accomplishing the task. More to the point, we use C++ because it's portable, and the language and library *do* make a difference because very specific features are used to solve the problem. See my answer.
Potatoswatter
A: 

A new iostream class can wrap that functionality. This assumes your prepend data isn't too large to comfortably fit in memory. Use it like a regular ofstream.

#include <fstream>
#include <sstream>
#include <vector>

class prepend_ofstream
    : public std::ostringstream {
    std::filebuf file;
public:
    prepend_ofstream() {}
    prepend_ofstream( char const *name, openmode mode = out ) {
        open( name, mode );
    }
    ~prepend_ofstream() {
        if ( is_open() ) close();
    }
    void open( char const *name, openmode mode ) {
        if ( ! file.open( name, mode & binary | in | out ) ) {
            setstate( failbit );
        }
    }
    bool is_open() { return file.is_open(); }
    void close() {
        if ( ! is_open() ) {
            setstate( failbit );
            return;
        }
        char *strbuf = &str()[0];
        std::vector<char> buf( str().size() );
        int rdsz;
        do {
            rdsz = file.sgetn( &buf[0], buf.size() );
            file.pubseekoff( -rdsz, cur );
            file.sputn( strbuf, buf.size() );
            file.pubseekoff( 0, cur ); // "update the output sequence"
            std::copy( &buf[0], &buf[0]+rdsz, strbuf );
        } while ( rdsz == buf.size() );
        file.sputn( &buf[0], rdsz );
        if ( ! file.close() ) {
            setstate( failbit );
        }
    }
};

Typically features are added through new stream buffer classes, not actual streams, but in this case the new functionality is in close, which is unfortunately not virtual.

Potatoswatter