我正在使用此程序将text.txt中的每个元音修改为主题标签('#')
CrystalReport1.ReportFileName = "D:\VISUAL BASIC\monrep.rpt"
CrystalReport1.RetrieveDataFiles
CrystalReport1.Action = 1
因此,如果text.txt的初始内容为
#include <fstream>
#include <iostream>
int main()
{
std::fstream iofile{ "text.txt", std::ios::in | std::ios::out };
char chChar;
while (iofile.get(chChar))
{
switch (chChar)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
iofile.seekp(-1, std::ios::cur);
iofile << '#';
iofile.seekg(iofile.tellg(), std::ios::beg);
}
}
}
它将变成
something is funny
问题是这条线
s#m#th#ng #s f#nny
此行将文件指针保持在同一位置,所以我想我可以将其更改为此行
iofile.seekg(iofile.tellg(), std::ios::beg);
我认为这会做同样的事情,但事实并非如此。当我运行该程序时,控制台仅在此处停止并且没有停止,并且text.txt开始打印奇怪的内容。但是当我用这一行替换它时,它又可以工作了
iofile.seekg(0, std::ios::cur);
我认为这应该将文件指针移得太远(我们应该将其保持在该位置,但在这里我们将其传递1个字母)。但是,这有效。发生什么事了?
答案 0 :(得分:1)
iofile << '#';
iofile.flush(); // flush buffer when switching from output to input
iofile.seekg(0, std::ios::cur);
我最近有一本书是关于iostream的,“标准C ++ IOStreams和Lcocales”。该书在第1.4.3节“双向文件流:从输出切换到输入”中进行了描述,
当输出已写入双向文件流时,在写入文件流后立即进行读取尝试将导致“不确定的结果”。 .... ....读取操作可能会失败,但无论如何都不会指示此失败;
作者提到,写入后必须在读取之前刷新流,并且还写道,调用seekg(0,ios_base :: beg)具有清空内部缓冲区的效果,但是我不确定是否在第二个参数(例如ios_base :: cur)上用不同的值调用的seekg()也可以。
答案 1 :(得分:1)
这是一个好问题!我可以使用Microsoft Visual Studio Community Edition 2019重现您的问题。但是,使用Visual Studio Code和g ++ 9.3.0,不会遇到相同的问题。似乎是编译器问题,尤其是Microsoft Visual C ++。
C++ standard是关于文件流限制的C标准库:
对读写器控制的序列的限制 class basic_filebuf
的对象与for相同 使用C标准库FILE进行读取和写入。
C标准库(7.19.5.3第6段)说:
以更新模式打开文件时(第二个或第三个为'+' 上面的模式参数值列表中的字符),输入和 输出可以在相关的流上执行。但是,输出 不得在没有中间调用的情况下直接输入 fflush功能或文件定位功能(fseek,fsetpos, 或快退),并且输入后不得直接输出 除非有输入,否则将直接调用文件定位功能 操作遇到文件尾。
换句话说:在文件流的输入和输出之间切换时,必须执行刷新或查找。现在,这一行:
iofile.seekg(0, std::ios::cur);
应该执行查找(相对于当前流位置的相同位置),但是对于似乎未发生的MSVC ++,随后将发生未定义的行为。但是,当您通过指定std::ios::beg
从文件的开头进行搜索时,实际上会执行搜索,并且程序将按预期运行。