向后读取文件,c++ ifstream
Reading file backwards , c++ ifstream
我想从文件中逆向读取 - 从结尾到开头。
这行得通,但我不仅想从文件中获取字符,还想在阅读时删除它们。
std::fstream fileA;
fileA.seekg(-1, fileA.end);
int size = fileA.tellg();
for (i = 1; i <= size; i++)
{
fileA.seekg(-i, fileA.end);
fileA.get(ch);
std::cout << ch;
}
有没有办法做到这一点,而不是复制内容并创建一个没有我所读内容的新文件?
如果您只想获取二进制数据并以相反的顺序呈现它,不管它的含义如何,您的代码都可以。
一些建议:
然后您应该在 binary
中打开流以实现跨平台的一致性(即避免在 windows 等平台上将换行符转换为双换行符,对其进行编码如 0x0d,0x0a
)。
你也可以考虑在循环中使用相对于当前位置的相对位置来向后导航,而不是总是走到最后并从最后的绝对位置重新定位自己。
这里是经过微调的代码:
ifstream fileA("test.txt", ios::binary); // binary data because binary revert
fileA.seekg(-1, ios::end); // position on last char to be read
char ch;
for (; fileA.get(ch); fileA.seekg(-2, ios::cur)) // try to read and rewind.
std::cout << ch;
但是您的代码无法读取正确的 UTF8 编码文件,因为多字节序列将被机械还原,并且它们的还原版本无效 UTF8:
- 如果您的文件中只有 ASCII 字符,这不是问题。
- 如果 UTF8 一致性对您来说是个问题,您可以考虑一个非常简单的 解决方法 :如果您读取
u
对应 (u & 0xC0) == 0x80
的字符,您必须读取所有前面的字符,直到此条件变为假,并以正确的顺序输出字节组(2 到 8 之间)。
操作方法如下:
... // If UTF-8 must be processed correctly
fileA.seekg(-1, ios::end);
char ch, buft[9]{},*p;
bool mb=false;
for (; fileA.get(ch); fileA.seekg(-2, ios::cur))
{
if (mb) { // if we are already processing a multibyte sequence
if ((ch & 0xC0) == 0x80 && p!=buft) // still another byte ?
*--p=ch;
else {
cout <<ch<<p; // if no other output the current leading char followed by the multibyte encoding that we've identified
mb=false; // and multibyte processing is then finished
}
}
else if ((ch & 0xC0) == 0x80) { // if a new multibyte sequence is identified
mb =true; // start its processing
buft[7]=ch;
p=buft+7;
}
else std::cout << ch; // normal chars ar procesed as before.
}
这里是runnable demo。
最后一点:从输入流中删除最后一个字节取决于操作系统。您应该查看 this SO question 以获得有关如何在 linux/posix 和 windows 上执行此操作的答案。
如果不使用概述的其中一种方法,这确实是不可能的 here or here。如果查看 istream_iterator,您会发现它是一个输入迭代器 (24.6.1)(1)
The class template istream_iterator is an input iterator
然后从 (24.2.1)(table 105)
Random Access -> Bidirectional -> Forward -> Input
-> Output
如您所见,输入迭代器是一种限制性更强的前向迭代器,前向迭代器只能朝一个方向前进。由于这种行为,它们不是从输入流末尾开始并向后走的标准方法
我想从文件中逆向读取 - 从结尾到开头。 这行得通,但我不仅想从文件中获取字符,还想在阅读时删除它们。
std::fstream fileA;
fileA.seekg(-1, fileA.end);
int size = fileA.tellg();
for (i = 1; i <= size; i++)
{
fileA.seekg(-i, fileA.end);
fileA.get(ch);
std::cout << ch;
}
有没有办法做到这一点,而不是复制内容并创建一个没有我所读内容的新文件?
如果您只想获取二进制数据并以相反的顺序呈现它,不管它的含义如何,您的代码都可以。
一些建议:
然后您应该在
binary
中打开流以实现跨平台的一致性(即避免在 windows 等平台上将换行符转换为双换行符,对其进行编码如0x0d,0x0a
)。你也可以考虑在循环中使用相对于当前位置的相对位置来向后导航,而不是总是走到最后并从最后的绝对位置重新定位自己。
这里是经过微调的代码:
ifstream fileA("test.txt", ios::binary); // binary data because binary revert
fileA.seekg(-1, ios::end); // position on last char to be read
char ch;
for (; fileA.get(ch); fileA.seekg(-2, ios::cur)) // try to read and rewind.
std::cout << ch;
但是您的代码无法读取正确的 UTF8 编码文件,因为多字节序列将被机械还原,并且它们的还原版本无效 UTF8:
- 如果您的文件中只有 ASCII 字符,这不是问题。
- 如果 UTF8 一致性对您来说是个问题,您可以考虑一个非常简单的 解决方法 :如果您读取
u
对应(u & 0xC0) == 0x80
的字符,您必须读取所有前面的字符,直到此条件变为假,并以正确的顺序输出字节组(2 到 8 之间)。
操作方法如下:
... // If UTF-8 must be processed correctly
fileA.seekg(-1, ios::end);
char ch, buft[9]{},*p;
bool mb=false;
for (; fileA.get(ch); fileA.seekg(-2, ios::cur))
{
if (mb) { // if we are already processing a multibyte sequence
if ((ch & 0xC0) == 0x80 && p!=buft) // still another byte ?
*--p=ch;
else {
cout <<ch<<p; // if no other output the current leading char followed by the multibyte encoding that we've identified
mb=false; // and multibyte processing is then finished
}
}
else if ((ch & 0xC0) == 0x80) { // if a new multibyte sequence is identified
mb =true; // start its processing
buft[7]=ch;
p=buft+7;
}
else std::cout << ch; // normal chars ar procesed as before.
}
这里是runnable demo。
最后一点:从输入流中删除最后一个字节取决于操作系统。您应该查看 this SO question 以获得有关如何在 linux/posix 和 windows 上执行此操作的答案。
如果不使用概述的其中一种方法,这确实是不可能的 here or here。如果查看 istream_iterator,您会发现它是一个输入迭代器 (24.6.1)(1)
The class template istream_iterator is an input iterator
然后从 (24.2.1)(table 105)
Random Access -> Bidirectional -> Forward -> Input
-> Output
如您所见,输入迭代器是一种限制性更强的前向迭代器,前向迭代器只能朝一个方向前进。由于这种行为,它们不是从输入流末尾开始并向后走的标准方法