std::fstream 从文件中读取数据块并将数据写回文件直到 EOF
std::fstream read block of data from file and write data back to file until EOF
我正在从文件中读取数据块,但不是一次全部读取(例如每个 read/write 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;
}
您知道覆盖错误的原因是什么吗?
编辑:
抱歉,我看不到链接的副本如何回答我的问题,我只是无法将给定的答案应用于上面的代码。
您的代码没有很好地处理 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;
}
但是,这并没有根本的不同。这两个版本对我来说都是一样的。我正在使用 g++ Linux。
从链接到可能的欺骗,我还建议在 for
循环结束 }
之前添加此内容:
file.seekp(file.tellp());
我已将其放入代码中的适当位置。
我正在从文件中读取数据块,但不是一次全部读取(例如每个 read/write 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;
}
您知道覆盖错误的原因是什么吗?
编辑: 抱歉,我看不到链接的副本如何回答我的问题,我只是无法将给定的答案应用于上面的代码。
您的代码没有很好地处理 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;
}
但是,这并没有根本的不同。这两个版本对我来说都是一样的。我正在使用 g++ Linux。
从链接到可能的欺骗,我还建议在 for
循环结束 }
之前添加此内容:
file.seekp(file.tellp());
我已将其放入代码中的适当位置。