std :: fstream читает блок данных из файла и записывает данные обратно в файл до EOF - PullRequest
0 голосов
/ 09 апреля 2019

Я читаю блоки данных из файла, но не все сразу (например, 3 байта на чтение / запись), а затем записываю те же 3 байта обратно в файл в ту же самую позицию внутри файла, а затем продолжаю цикл до тех пор, пока не останется больше блоков для чтения.

Другими словами, я пытаюсь переписать файл по самому содержанию.

Однако существует проблема, заключающаяся в том, что конечный результат не совпадает с тем, который был в начале.

Следующий пример кода читает 3 байта за итерацию из файла «sample.txt», содержимое файла простое:

0123456789

после чтения данных и записи данных обратно в файл, содержимое:

012345345345

Как вы видите, данные по какой-то причине перезаписываются неправильно.

#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;
}

Видите ли вы, в чем причина плохой перезаписи?

EDIT: Извините, я не вижу, как связанный дубликат отвечает на мой вопрос, я просто не могу применить данный ответ к приведенному выше коду.

1 Ответ

0 голосов
/ 09 апреля 2019

Ваш код плохо обрабатывает условие EOF и оставляет поток в плохом состоянии после попытки чтения после конца файла. В моей системе это приводит к тому, что все дальнейшие вызовы потока не имеют никакого эффекта. Могу поспорить, что это не так в вашей системе (что, я подозреваю, является ошибкой в ​​ее реализации iostream). Я переделал ваш код для правильной обработки условия EOF, а также для того, чтобы быть намного чище несколькими другими способами:

#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;
}

Но это не принципиально отличается. Обе версии работают для меня точно так же. Я на Linux с g ++.

Из связанного с возможным дублированием я бы также предложил добавить это непосредственно перед закрытием } вашего for цикла:

file.seekp(file.tellp());

Я поместил это в свой код в соответствующем месте.

...