为什么 std::ofstream 会在没有 std::ios_base::trunc 的情况下截断?
Why does std::ofstream truncate without std::ios_base::trunc?
根据这个 C++ 参考资料:http://www.cplusplus.com/reference/fstream/ofstream/ofstream/,std::ofstream
的默认打开模式是 ios_base::out
,它没有提到任何隐含的其他模式。因此,我希望如果我用一个小文件覆盖一个大文件,大文件的 "exceeding" 部分应该保持不变,只有文件的第一部分应该被新的、更短的数据替换。
另一方面,Apache C++ 标准库用户指南 (http://stdcxx.apache.org/doc/stdlibug/30-3.html) 在第 30.3.1.2 段的注释中指出:"For output file streams the open mode out is equivalent to out|trunc, that is, you can omit the trunc flag. For bidirectional file streams, however, trunc must always be explicitly specified."
我试过这个代码:
#include <fstream>
int main()
{
std::ofstream aFileStream("a.out", std::ios_base::out);
aFileStream << "Hello world!";
aFileStream.close();
std::ofstream aFileStream2("a.out", std::ios::out);
aFileStream2 << "Bye!";
aFileStream2.close();
}
两者,Windows 上的 g++ 8.1 和 Linux 上的 g++ 6.3,Apache 文档似乎是正确的。大文件被截断,用第二个文件流写入较短的字符串后什么都没有。
为什么会这样? cplusplus.com错了吗?或者这种行为取决于什么?
根据 [ofstream.cons]/itemdecl:2:
explicit basic_ofstream(const char* s,
ios_base::openmode mode = ios_base::out);
因此,ofstream
的默认模式是 out
。但是,根据 [tab:filebuf.open.modes], out
and out | trunc
both correspond to the stdio equivalent "w"
, so they are equivalent. Per C11 7.21.5.3:
w
: truncate to zero length or create text file for writing
因此,说默认模式是out
是正确的,说默认模式等同于out | trunc
也是正确的。这是有保证的行为。
另一方面,根据 [fstream.cons]/itemdecl:2:
explicit basic_fstream(
const char* s,
ios_base::openmode mode = ios_base::in | ios_base::out);
因此,fstream
的默认模式是 in | out
。每 [tab:filebuf.open.modes], in | out
corresponds to "r+"
, while in | out | trunc
corresponds to "w+"
, so they are not equivalent. Per C11 7.21.5.3:
r+
: open text file for update (reading and writing)
w+
: truncate to zero length or create text file for update
因此,除非您指定 trunc
,否则 fstream
不会截断。
请注意,如果所需文件不存在,r+
将失败而不是创建文件。相比之下,w
和 w+
在这种情况下都会创建一个新文件。
(另请参阅:fopen
on cppreference)
根据这个 C++ 参考资料:http://www.cplusplus.com/reference/fstream/ofstream/ofstream/,std::ofstream
的默认打开模式是 ios_base::out
,它没有提到任何隐含的其他模式。因此,我希望如果我用一个小文件覆盖一个大文件,大文件的 "exceeding" 部分应该保持不变,只有文件的第一部分应该被新的、更短的数据替换。
另一方面,Apache C++ 标准库用户指南 (http://stdcxx.apache.org/doc/stdlibug/30-3.html) 在第 30.3.1.2 段的注释中指出:"For output file streams the open mode out is equivalent to out|trunc, that is, you can omit the trunc flag. For bidirectional file streams, however, trunc must always be explicitly specified."
我试过这个代码:
#include <fstream>
int main()
{
std::ofstream aFileStream("a.out", std::ios_base::out);
aFileStream << "Hello world!";
aFileStream.close();
std::ofstream aFileStream2("a.out", std::ios::out);
aFileStream2 << "Bye!";
aFileStream2.close();
}
两者,Windows 上的 g++ 8.1 和 Linux 上的 g++ 6.3,Apache 文档似乎是正确的。大文件被截断,用第二个文件流写入较短的字符串后什么都没有。
为什么会这样? cplusplus.com错了吗?或者这种行为取决于什么?
根据 [ofstream.cons]/itemdecl:2:
explicit basic_ofstream(const char* s, ios_base::openmode mode = ios_base::out);
因此,ofstream
的默认模式是 out
。但是,根据 [tab:filebuf.open.modes], out
and out | trunc
both correspond to the stdio equivalent "w"
, so they are equivalent. Per C11 7.21.5.3:
w
: truncate to zero length or create text file for writing
因此,说默认模式是out
是正确的,说默认模式等同于out | trunc
也是正确的。这是有保证的行为。
另一方面,根据 [fstream.cons]/itemdecl:2:
explicit basic_fstream( const char* s, ios_base::openmode mode = ios_base::in | ios_base::out);
因此,fstream
的默认模式是 in | out
。每 [tab:filebuf.open.modes], in | out
corresponds to "r+"
, while in | out | trunc
corresponds to "w+"
, so they are not equivalent. Per C11 7.21.5.3:
r+
: open text file for update (reading and writing)
w+
: truncate to zero length or create text file for update
因此,除非您指定 trunc
,否则 fstream
不会截断。
请注意,如果所需文件不存在,r+
将失败而不是创建文件。相比之下,w
和 w+
在这种情况下都会创建一个新文件。
(另请参阅:fopen
on cppreference)