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

11
根据这个 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是错误的吗?还是行为取决于什么?


根据 cppreference 的说明,out 模式会删除已存在文件中的内容(覆盖所有内容)。 - DColt
1个回答

12

根据[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 + 将失败而不是创建文件。相比之下,在这种情况下,w w + 都会创建一个新文件。

(另请参见:fopen在cppreference上的资料)


好的回答 - 你能否也提供引用的C标准的链接?那样回答会更好。 - Felix Dombek
1
@FelixDombek 添加了标准和cppreference的链接。 - L. F.
1
谢谢,太棒了 - 等等,你的哈希锚点名称是如何工作的?!它看起来完全不像 https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/pdf_open_parameters.pdf 中给出的标准。 - Felix Dombek
1
@FelixDombek 神奇 :) 我使用Firefox,在左侧的导航面板上右键单击,选择“复制链接位置”,然后就完成了。 - L. F.
另一个小注释:值得指出的是,与ofstream不同,带有in|out的fstream如果文件不存在将不会创建该文件(而是会失败)。因此,它不是一种1:1的替代品。 - Felix Dombek
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接