我正在尝试打开输出文件并附加到它。在附加到它之后,我想将输出位置移动到文件中的其他位置,并且覆盖现有数据。据我了解,std::ios_base::app
强制 所有写入都在文件末尾不我想要的做。因此,我认为std::ios_base::ate
是传递给std::ofstream::open()
的正确标志。但是,它似乎没有按预期工作:
// g++ test.cpp
// clang++ test.cpp
// with and without -std=c++11
#include <iostream>
#include <fstream>
int main() {
std::streampos fin, at;
{
std::ofstream initial;
initial.open("test", std::ios_base::out | std::ios_base::binary);
if ( not initial.good() ) {
std::cerr << "initial bad open" << std::endl;
return 1;
}
int b = 100;
initial.write((char*)&b, sizeof(b));
initial.flush();
if ( not initial.good() ) {
std::cerr << "initial write bad" << std::endl;
return 1;
}
fin = initial.tellp();
}
{
std::ofstream check;
check.open("test", std::ios_base::out | std::ios_base::binary | std::ios_base::ate);
if ( not check.good() ) {
std::cerr << "check bad open" << std::endl;
return 1;
}
at = check.tellp();
if ( fin != at ) {
std::cerr << "opened at wrong position!\nfin:\t" << fin << "\n" << "at:\t" << at << std::endl;
return 1;
}
int bb = 200;
check.write((char*)&bb, sizeof(bb));
check.flush();
if ( not check.good() ) {
std::cerr << "check write bad" << std::endl;
return 1;
}
at = check.tellp();
}
if ( (fin + std::streampos(sizeof(int))) != at ) {
std::cerr << "overwrite?\nfin:\t" << fin << "\n" << "at:\t" << at << std::endl;
return 1;
}
return 0;
}
特别是,std::ios_base::ate
似乎不将初始输出指针移动到结尾,如上所示。显然这会导致第一次写入覆盖文件的开头(这是导致我麻烦的原因)。
似乎实现不正确或者cplusplus.com不正确(&#34;输出位置从文件末尾开始。&#34; )和{ {3}}含糊不清(&#34;在打开后立即寻找流的末尾&#34; :哪个流?)。
显然有一个简单的解决方法:只使用stream.seekp(0, std::ios_base::end)
。
所以我的问题是:我的代码是不正确的?实施不正确吗?参考网站是否不正确?任何见解都将不胜感激。
答案 0 :(得分:7)
如下图所示,您可以在N4296 [filebuf.members]
中看到
组合binary | out
将在stdio
等效"wb"
打开文件,truncate to zero length or create binary file for writing
(N1570 7.21.5.2)。
与ofstream
听起来一样违反直觉,如果您不希望截断文件,则需要添加in
标记,如果您希望截断文件,则需要app
想要避免截断并在每次写入时寻找文件的末尾。
额外提示:与fstream
不同,ifstream
和ofstream
会自动或std::ios_base::in
和std::ios_base::out
分别为您提供给构造函数或{的open
和std::ofstream check("test", check.in | check.binary | check.ate);
{1}}。您还可以使用对象本身来访问标志:
good
if (!initial)
的支票也可以缩短为{{1}}等。