Вырастить файл для дальнейшей записи с использованием boost :: mapped_region? - PullRequest
0 голосов
/ 14 сентября 2018

Мне нужно создать и записать в файл отображения памяти. Иногда необходимо увеличить файл.

Я создал следующий небольшой тест, в котором я создаю файл, отображаю его с помощью boost::mapped_region и записываю в него.

Это все работает как ожидалось:

#include <fstream>
#include <boost/interprocess/file_mapping.hpp>
#include <boost/interprocess/mapped_region.hpp>

namespace bip = boost::interprocess;

void createFile(const char* fn, std::uint64_t num)
{
    std::filebuf fbuf;
    fbuf.open(fn, std::ios_base::out|std::ios_base::binary|std::ios_base::trunc);

    const std::uint64_t size = sizeof(std::uint64_t) * (num + 1);

    fbuf.pubseekoff(size - 1, std::ios_base::beg);
    fbuf.sputc(0);
    fbuf.close();
}

void writeToFile(const char* fn, std::uint64_t pos, std::uint64_t val)
{
    bip::file_mapping  fm(fn, bip::read_write);
    bip::mapped_region rg(fm, bip::read_write);

    std::uint64_t* p = reinterpret_cast<std::uint64_t*>(rg.get_address());

    *p = std::max(*p, pos); // store max num values
    *(p + pos) = val;       // write value into position
}

int main ()
{
    const char* fn = "/tmp/test.dat";

    createFile(fn, 3);
    writeToFile(fn, 1, 0x1111111111111111);
    writeToFile(fn, 2, 0x2222222222222222);
    writeToFile(fn, 3, 0x3333333333333333);

    return 0;
}

При запуске этой программы создается выходной файл, как и ожидалось, и когда я выкидываю его содержимое, я вижу правильно записанные в нем значения:

$ xxd -p /tmp/test.dat 
030000000000000011111111111111112222222222222222333333333333
3333

Однако теперь я хочу изменить размер файла, чтобы в конце я мог записать дополнительные данные.

Я добавляю следующую функцию, growFile (которая использует ios_base::app, как предложено timrau ниже)

void growFile(const char* fn, std::uint64_t num)
{
    std::filebuf fbuf;
    fbuf.open(fn, std::ios_base::out|std::ios_base::binary|std::ios_base::app);

    const std::uint64_t size = sizeof(std::uint64_t) * (num + 1);

    fbuf.pubseekoff(size - 1, std::ios_base::beg);
    fbuf.sputc(0);
    fbuf.close();
}

Теперь я добавляю дополнительные значения после увеличения файла:

int main ()
{
    const char* fn = "/tmp/test.dat";

    createFile(fn, 3);
    writeToFile(fn, 1, 0x1111111111111111);
    writeToFile(fn, 2, 0x2222222222222222);
    writeToFile(fn, 3, 0x3333333333333333);

    growFile(fn, 6);
    writeToFile(fn, 4, 0x4444444444444444);
    writeToFile(fn, 5, 0x5555555555555555);
    writeToFile(fn, 6, 0x6666666666666666);

    return 0;
}

Когда я выкидываю файл, в нем пропускаются большинство новых значений.

$ xxd -p /tmp/test.dat 
060000000000000011111111111111112222222222222222333333333333
333344

Обратите внимание, что если я не увеличиваю файл, а просто создаю его сначала с достаточным пространством, он работает как положено:

int main ()
{
    const char* fn = "/tmp/test.dat";

    createFile(fn, 6);
    writeToFile(fn, 1, 0x1111111111111111);
    writeToFile(fn, 2, 0x2222222222222222);
    writeToFile(fn, 3, 0x3333333333333333);
    writeToFile(fn, 4, 0x4444444444444444);
    writeToFile(fn, 5, 0x5555555555555555);
    writeToFile(fn, 6, 0x6666666666666666);

    return 0;
}

Когда я выгружаю файл, все значения там есть:

$ xxd -p /tmp/test.dat 
060000000000000011111111111111112222222222222222333333333333
3333444444444444444455555555555555556666666666666666

Как я могу увеличить свой файл после создания, чтобы я мог написать дальше, чем его первоначальный размер?

Ответы [ 2 ]

0 голосов
/ 14 сентября 2018

У меня была другая игра на колиру.

Вы должны открыть файл для чтения / записи - эквивалентно :: fopen (..., "r +")

Все эти опции работают:

void resizeFile(const char* fn)
{
    constexpr auto offset = sizeof(std::uint64_t) * 6 - 1;

    /*
    FILE* fp = ::fopen(fn, "r+");
    ::fseek(fp, offset, SEEK_SET);
    ::fputc(0, fp);
    ::fclose(fp);
    */

/*
    std::fstream f;
    f.exceptions(std::ios::failbit | std::ios::badbit);
    f.open(fn, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
    f.seekp(offset, std::ios_base::beg);
    f.put(0);
    f.flush();
*/

    std::filebuf fbuf;
    fbuf.open(fn, std::ios_base::in | std::ios_base::out | std::ios_base::binary);
    fbuf.pubseekoff(offset, std::ios_base::beg);
    fbuf.sputc(0);
    fbuf.close();
}

http://coliru.stacked -crooked.com / а / ae224032dd036639

0 голосов
/ 14 сентября 2018

Когда resizeFile(), вы должны открыть файл в режиме добавления. В противном случае файл будет усечен до пустого файла в open().

fbuf.open(fn, std::ios_base::out | std::ios_base::binary | std::ios_base::app);
...