-3

In C++ I want to open and write to a file byte-by-byte some data. But when I open a file and write something to it the previous content is being lost. How can I prepend the new data to the beginning of a file and shift previous content.Is it possible? How to do it?

ofstream file;
file.open("test.daf",app);
file.seekp(0);
file << 'A';
Hans Klünder
  • 2,176
  • 12
  • 8
  • possible duplicate of [C#: Prepending to beginning of a file](http://stackoverflow.com/questions/1343044/c-prepending-to-beginning-of-a-file) – OmnipotentEntity Jan 01 '15 at 13:05
  • @OmnipotentEntity It's not C#, it's not prepending. In short, are you confused? – sehe Jan 01 '15 at 13:10
  • Actually, he means prepending, he just uses bad english. And there is no such file operation. user, you have to create a new file, write the new content and then append (really append) the old content. – Hans Klünder Jan 01 '15 at 13:12
  • @HansKlünder you're right. Still not c# of course – sehe Jan 01 '15 at 13:13
  • @HansKlünder I've given just one approach that resizes the file inplace :) It's not going to perform, but at least you don't have to create a new file – sehe Jan 01 '15 at 13:33
  • @sehe, I'm not confused. It is a different language, but the question is the same and not really dependent on the language. – OmnipotentEntity Jan 01 '15 at 13:37
  • 1
    @OmnipotentEntity fair enough. Anyways, that question lacks creative answers, apparently :) – sehe Jan 01 '15 at 13:39

2 Answers2

2

You can memory map the file, and shift the contents:

int main() {
    prepend("data.dat", { 1,2,3,4,5,6 });
}

Implemented with boost:

Live On Coliru

void prepend(path fname, std::vector<uint8_t> const& prepend_data)
{
    using namespace boost::iostreams;
    auto size    = file_size(fname);
    auto resized = size + prepend_data.size();

    resize_file(fname, resized);
    mapped_file mf(fname.native());

    std::rotate(mf.data(), mf.data() + size, mf.data() + resized);
    std::copy(prepend_data.begin(), prepend_data.end(), mf.data());
}

BONUS

Alternative version without the use of Boost (or, actually C++ at all, outside the static_cast):

Live On Coliru

#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

void prepend(const char* fname, char const* prepend_data, size_t n)
{
    struct stat s;
    stat(fname, &s);
    size_t size    = s.st_size;
    size_t resized = size + n;

    truncate(fname, resized);
    int fd = open(fname, O_RDWR);
    char* mapped_file = static_cast<char*>(mmap(NULL, resized, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));

    memmove(mapped_file + n, mapped_file, size);
    memcpy (mapped_file, prepend_data, n);
}

int main() {
    char const to_prepend[] = { 1,2,3,4,5,6 };
    prepend("data.dat", to_prepend, sizeof to_prepend);
}
sehe
  • 374,641
  • 47
  • 450
  • 633
-1

Files does not work that way, like strings, etc.

What you will have to do is to load the content of the file, put your preceeding content into the file and then put back the old content of the file right after that.

Depending on your filesize or performance, you might just load the whole file into a string (if it's all text and not binary) and append that string onto your string and then just write the complete string to the file. Example: string out_data = your_data + file_data;

Or binary like this:

std::fstream f;
f.open ("test.daf", std::fstream::in | std::fstream::out | std::fstream::app);
f.seekg (0, f.end);
int length = f.tellg();
f.seekg (0, f.beg);

char * buffer = new char [length];
f.read (buffer,length);
f << 'A'; // Like you wanted it

// Or more binary data
char data[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
f.write(data, 10);

f.write(buffer, length); // Finally put back the original content

f.close();

The above is not tested and is probably not the most optimum solution. I would not use this more than once in a program for performance reasons.

Christopher Janzon
  • 1,039
  • 11
  • 22