std :: fstream从文件读取数据块并将数据写回到文件,直到EOF

时间:2019-04-09 18:13:33

标签: c++ fstream

我正在从文件中读取数据块,但不是一次全部读取(例如,每次读/写3个字节),然后将相同的3个字节写回到文件中文件中的相同位置,然后继续循环直到没有更多的块要读取。

换句话说,我正试图通过文件的内容来重写它。

但是,最终的输出与开始时的输出不一样。

以下示例代码每次从文件“ sample.txt”读取3个字节,文件内容很简单:

  

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

您知道覆盖错误的原因是什么吗?

编辑: 抱歉,我看不到链接的重复项如何回答我的问题,我只是无法将给定的答案应用于上述代码。

1 个答案:

答案 0 :(得分:0)

您的代码不能很好地处理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());

我已将其放在代码中的适当位置。