在这种情况下,为什么seekp()失败?

时间:2020-08-02 03:43:49

标签: c++ file file-pointer

我正在使用此程序将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个字母)。但是,这有效。发生什么事了?

2 个答案:

答案 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从文件的开头进行搜索时,实际上会执行搜索,并且程序将按预期运行。

相关问题