为什么没有std :: ios_base :: trunc的std :: ofstream截断?

时间:2019-07-17 06:41:50

标签: c++ ofstream

根据此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错误吗?还是在行为上pent悔?

1 个答案:

答案 0 :(得分:7)

[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",因此它们等效。根据{{​​3}}:

  

w:截短为零长度或创建要写入的文本文件

因此,可以说默认模式为out,也可以说默认模式等效于out | trunc。这是有保证的行为。

另一方面,根据C11 7.21.5.3

explicit basic_fstream(
  const char* s,
  ios_base::openmode mode = ios_base::in | ios_base::out);

因此,fstream的默认模式是in | out。对于每个[fstream.cons]/itemdecl:2in | out对应于"r+",而in | out | trunc对应于"w+",因此它们不是等效的。根据{{​​3}}:

  

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

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

(另请参见:[tab:filebuf.open.modes]关于cppreference)