为什么 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
,并且没有提到隐式的其他模式。因此,我希望如果我用小文件覆盖大文件,大文件的"超出"部分应该保持不变,只有文件的第一部分应该被新的、较短的数据替换。
另一方面,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],out
和out | 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+
都会创建一个新文件。
(另请参阅:关于 cpp 首选项的fopen
)
- 如果 std::vector::clear() 不是静态的,如何在没有实例的情况下调用它?
- 在没有未定义行为的情况下实现类似std::vector的容器
- 如何在没有死锁和/或争用的情况下正确使用 std::mutex C++?
- C++标准是否允许<double>在没有开销的情况下实现 std::可选
- 在这种情况下显式调用时,std::cout 如何更改析构函数的行为?
- 为什么在以下情况下我需要使用 std::d ecay?
- 如何在没有 std::move 的情况下移动临时对象
- 在不使用模板的情况下获取 std::array 引用
- 如何在不使用 std::tm 和 mktime() 的情况下为给定日历日期创建 chrono::time_point 对
- 如何在给定 std::variant 的情况下检索模板参数包?
- 有没有办法在不使用命名空间 std 或前缀 std:: 的情况下引用 cout?
- 在不使用vector.end()的情况下迭代std::vector
- 为什么std::atomic中的所有成员函数都同时出现在有volatile和没有volatile的情况下
- 如何从 std::optional 中获取 QByteArray<QByteArray>,并在没有其他 malloc 的情况下保留 std::nullopt?
- 默认情况下,"std::shared_ptr"不应该使用"std::d efault_delete"吗?
- 推荐的方法在不初始化值的情况下使数组类型为 std::unique_ptr?
- 在运行时,何时完全初始化 std 库才能在不破坏代码的情况下使用它?
- 如何在没有迭代器的情况下使用 std::for_each + std::execution::p ar?
- 是否有可能在没有复制的情况下传递 std::vector<int> 作为参数来获得 std::vector<std::array<int, 3>>?
- std::regex 是否保证了最坏情况下的时间复杂度?