为什么 std::ofstream 会在没有 std::ios_base::trunc 的情况下截断?

Why does std::ofstream truncate without std::ios_base::trunc?

本文关键字:std 情况下 trunc base ios ofstream 为什么      更新时间:2023-10-16

根据C++参考:http://www.cplusplus.com/reference/fstream/ofstream/ofstream/,std::ofstream的默认打开模式是ios_base::out,并且没有提到隐式的其他模式。因此,我希望如果我用小文件覆盖大文件,大文件的"超出"部分应该保持不变,只有文件的第一部分应该被新的、较短的数据替换。

另一方面,Apache C++标准库用户指南 (http://stdcxx.apache.org/doc/stdlibug/30-3.html) 在第 30.3.1.2 段的注释中指出:"对于输出文件流,打开模式 out 等同于 out|trunc,也就是说,您可以省略 trunc 标志。但是,对于双向文件流,必须始终显式指定 trunc。

我试过这段代码:

#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 错了吗?或者行为靠什么?

Per [ofstream.cons]/itemdecl:2:

explicit basic_ofstream(const char* s,
ios_base::openmode mode = ios_base::out);

因此,ofstream的默认模式是out。 然而,根据 [tab:filebuf.open.modes],outout | trunc都对应于 stdio 等效"w",所以它们是等价的。 根据 C11 7.21.5.3:

w:截断为零长度或创建文本文件进行写入

因此,说默认模式是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对应于"r+",而in | out | trunc对应于"w+",所以它们不等价。 根据 C11 7.21.5.3:

r+:打开文本文件进行更新(读取和写入)
w+:截断为零长度或创建文本文件进行更新

因此,除非指定trunc,否则fstream不会截断。 请注意,如果所需的文件不存在,则r+将失败,而不是创建文件。 相比之下,在这种情况下,ww+都会创建一个新文件。

(另请参阅:关于 cpp 首选项的fopen)

相关文章: