stream :: seekoff是否更新输入序列?

时间:2018-07-25 08:00:54

标签: c++ stream buffer language-lawyer

[filebuf.virtuals]中:

pos_type seekoff(off_type off, ios_base::seekdir way,
                 ios_base::openmode which
                   = ios_base::in | ios_base::out) override;
     

效果:width表示a_­codecvt.encoding()。如果为is_­open() == falseoff != 0 && width <= 0,则定位操作失败。否则,如果way != basic_­ios​::​curoff != 0,并且如果输出了最后一个操作,则更新输出序列并写入所有未移位序列。接下来,寻找新位置:如果为width > 0,请致电fseek(file, width * off, whence),否则请致电fseek(file, 0, whence)

它没有提及此功能更新输入序列。相反,seekpos确实更新了输入序列:

pos_type seekpos(pos_type sp,
                 ios_base::openmode which
                   = ios_base::in | ios_base::out) override;
     

如果可能,更改文件位置,使其与sp中存储的位置相对应(如下所述)。更改文件位置的操作如下:

     
      
  1. 如果为(om & ios_­base​::​out) != 0,则更新输出序列并写入所有未移位序列;

  2.   
  3. 将文件位置设置为sp,就像通过调用fsetpos;

  4.   
  5. 如果为(om & ios_­base​::​in) != 0,则更新输入顺序

  6.   

那么seekoff是否可以保证更新输入序列?

例如,请考虑:

#include <fstream>
#include <iostream>

int main()
{
    std::fstream f("test.txt"); // test.txt contains "test"
    char ch;
    f >> ch;
    f.rdbuf()->pubseekoff(0, std::ios_base::beg);
    f >> ch;
    std::cout << ch;
}

程序是否已保证输出

1 个答案:

答案 0 :(得分:2)

我可以看到你的主要朋友,确实这可能会引起一些困惑,不仅是你自己。

简短答案:

是的,seekoff将更新输入序列,就像seekpos一样。关于seekoffseekpos的行为在调用,输入或输出(或两者)正在更新的序列上是相同的。

详细解释

不是单独通过约定,而是根据标准本身,将seekoffseekpos的行为定义为依赖于ios_base::openmode which参数。从另一个与stringbuf相同的父类派生的类模板filebuf中可以看出,the override for seekoff明确指出对于(which & ios_­base​::​in) == ios_­base​::​in ,调用将放置输入顺序;对于(which & ios_­base​::​out) == ios_­base​::​out该调用将定位输出序列;对于(which & (ios_­base​::​in | ios_­base​::​out)) == (ios_­base​::​in | ios_­base​::​out)way ==的{​​{1}}和ios_­base​::​beg该调用将同时定位输入序列和输出序列。

但是当直接在标准之前工作时,人们不必期望事情会自我展示。请参见父类streambuf下的内容:

ios_­base​::​end
     

效果:更改一个或多个受控序列中的流位置,方法是为从pos_type seekoff(off_type off, ios_base::seekdir way, ios_base::openmode which = ios_base::in | ios_base::out) override; 派生的每个类分别定义

因此,通过更仔细地查看the quote you have provided yourself regarding seekpos of filebuf的标准:

basic_­streambuf
     

如果可能,更改文件位置,使其与pos_type seekpos(pos_type sp, ios_base::openmode which = ios_base::in | ios_base::out) override; 中存储的位置相对应(如下所述)。更改文件位置的操作如下:

     
      
  1. 如果为sp,则更新输出序列并写入所有未移位序列;

  2.   
  3. 将文件位置设置为(om & ios_­base​::​out) != 0,就像通过调用sp;

  4.   
  5. 如果fsetpos,则更新输入序列;

  6.   

以下行说:

  

其中(om & ios_­base​::​in) != 0是传递给上次对open()的调用的打开模式。 ...

因此,这意味着您无法在呼叫本身中指定要更新的序列。就像在此一样,此处的标准表示实现应简单地忽略(!) om参数。

在您提供的关于om的引言中,我们不容错过的另一句话是:

  

下一步,寻找新位置:如果seekoff呼叫width > 0 ,否则呼叫 fseek(file, width * off, whence)

因此,底层只是对fseek的调用。但是在哪个特定的FILE对象上呢?是否有单独的输入和输出?我相信我们正在寻找的答案会出现在filebuf下的规范中:

  

§27.9.1.1

     
      
  1. basic_filebuf类将输入序列和   输出序列和文件。
  2.   
  3. 对读写由类对象控制的序列的限制   basic_filebuf与使用标准C库进行读取和写入相同   文件。
  4.   
  5. 尤其是:      
        
    • 如果未打开文件以读取输入序列,则无法读取。
    •   
    • 如果未打开文件进行写入,则无法写入输出序列。
    •   
    • 输入序列和输出序列都保持联合文件位置。
    •   
  6.   

与之类似,fseek(file, 0, whence)seekoff在调用,输入或输出(或两者)正在更新哪个序列方面表现相同,并且仅由传递给{ {1}}。

此外,大约5年前刚遇到此问题,我看到:fstream seekg(), seekp(), and write()

编辑,以进一步说明:

请注意seekpos的规范说:

  

如果输出了最后一个操作,则更新输出顺序并   写下任何不移位的顺序。

open()也说:

  

更新输出序列并写入所有未移位序列;

the remarks section for seekoff定义了“写任何不移位序列”的含义。因此,这两种方法都应等效。但随后两者都进一步指定:seekoff说它调用seekpos,而seekoff说它调用fseek(在这方面与seekpos相同)。

考虑到上面提到的第27.9.1.1节中的第2点,在C11标准ISO中对此进行了解释,甚至找到提到了最后一个操作已输出位的原因。 / IEC 9899:2011:

  

§7.21.5.3fsetpos函数

     

¶7当以更新模式打开文件时,(“ +”作为第二个或第三个字符   上面的模式参数值列表),输入和输出都可以在   相关流。但是,在没有输入的情况下,输出后不能直接跟随输入   介入对fseek函数或文件定位函数(fopen的调用,   fflushfseek),并且在没有输入的情况下,输入后不得直接跟随输出   除非输入操作遇到文件结尾,否则将调用文件定位函数。

因此,要在下面回答您的评论,无论是否输入了最后一个操作,fsetpos是否都会更新输入序列。如果未输入最后一个操作,则上面讨论的未移位序列具有技术性。但是,整个rewind类的部分想法是,以一种不会打扰您的维护工作的方式封装I / O。