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() == false
或off != 0 && width <= 0
,则定位操作失败。否则,如果way != basic_ios::cur
或off != 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
中存储的位置相对应(如下所述)。更改文件位置的操作如下:
如果为
(om & ios_base::out) != 0
,则更新输出序列并写入所有未移位序列;将文件位置设置为
sp
,就像通过调用fsetpos
;如果为
(om & ios_base::in) != 0
,则更新输入顺序;
那么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
一样。关于seekoff
和seekpos
的行为在调用,输入或输出(或两者)正在更新的序列上是相同的。
详细解释:
不是单独通过约定,而是根据标准本身,将seekoff
和seekpos
的行为定义为依赖于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;
中存储的位置相对应(如下所述)。更改文件位置的操作如下:
如果为
sp
,则更新输出序列并写入所有未移位序列;将文件位置设置为
(om & ios_base::out) != 0
,就像通过调用sp
;如果
fsetpos
,则更新输入序列;
以下行说:
其中
(om & ios_base::in) != 0
是传递给上次对open()的调用的打开模式。 ...
因此,这意味着您无法在呼叫本身中指定要更新的序列。就像在此一样,此处的标准表示实现应简单地忽略(!) om
参数。
在您提供的关于om
的引言中,我们不容错过的另一句话是:
下一步,寻找新位置:如果
seekoff
,呼叫width > 0
,否则呼叫fseek(file, width * off, whence)
。
因此,底层只是对fseek
的调用。但是在哪个特定的FILE对象上呢?是否有单独的输入和输出?我相信我们正在寻找的答案会出现在filebuf下的规范中:
§27.9.1.1
- basic_filebuf类将输入序列和 输出序列和文件。
- 对读写由类对象控制的序列的限制 basic_filebuf与使用标准C库进行读取和写入相同 文件。
- 尤其是:
- 如果未打开文件以读取输入序列,则无法读取。
- 如果未打开文件进行写入,则无法写入输出序列。
- 输入序列和输出序列都保持联合文件位置。
与之类似,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.3
fsetpos
函数¶7当以更新模式打开文件时,(“ +”作为第二个或第三个字符 上面的模式参数值列表),输入和输出都可以在 相关流。但是,在没有输入的情况下,输出后不能直接跟随输入 介入对
fseek
函数或文件定位函数(fopen
的调用,fflush
或fseek
),并且在没有输入的情况下,输入后不得直接跟随输出 除非输入操作遇到文件结尾,否则将调用文件定位函数。
因此,要在下面回答您的评论,无论是否输入了最后一个操作,fsetpos
是否都会更新输入序列。如果未输入最后一个操作,则上面讨论的未移位序列具有技术性。但是,整个rewind
类的部分想法是,以一种不会打扰您的维护工作的方式封装I / O。