c++ - 带有 std::ate 的 std::ofstream 未在末尾打开

标签 c++ c++11 fstream

我正在尝试打开一个文件进行输出并附加到它。附加到它之后,我想将我的输出位置移动到文件中的其他位置并覆盖 现有数据。据我了解,std::ios_base::app强制 所有写入到文件的末尾,即 不是我想做的。因此,我相信 std::ios_base::ate 是传递给 std::ofstream::open() 的正确标志。但是,它似乎没有按预期工作:

// g++ test.cpp
// clang++ test.cpp
// with and without -std=c++11
#include <iostream>
#include <fstream>

int main() {
    std::streampos fin, at;
    {
        std::ofstream initial;
        initial.open("test", std::ios_base::out | std::ios_base::binary);
        if ( not initial.good() ) {
            std::cerr << "initial bad open" << std::endl;
            return 1;
        }
        int b = 100;
        initial.write((char*)&b, sizeof(b));
        initial.flush();
        if ( not initial.good() ) {
            std::cerr << "initial write bad" << std::endl;
            return 1;
        }
        fin = initial.tellp();
    }
    {
        std::ofstream check;
        check.open("test", std::ios_base::out | std::ios_base::binary | std::ios_base::ate);
        if ( not check.good() ) {
            std::cerr << "check bad open" << std::endl;
            return 1;
        }
        at = check.tellp();
        if ( fin != at ) {
            std::cerr << "opened at wrong position!\nfin:\t" << fin << "\n" << "at:\t" << at << std::endl;
            return 1;
        }
        int bb = 200;
        check.write((char*)&bb, sizeof(bb));
        check.flush();
        if ( not check.good() ) {
            std::cerr << "check write bad" << std::endl;
            return 1;
        }
        at = check.tellp();
    }
    if ( (fin + std::streampos(sizeof(int))) != at ) {
        std::cerr << "overwrite?\nfin:\t" << fin << "\n" << "at:\t" << at << std::endl;
        return 1;
    }
    return 0;
}

特别是,std::ios_base::ate 似乎没有将初始输出指针移动到上面示例的末尾。显然,这会导致第一次写入覆盖文件的开头(这是我遇到麻烦的原因)。

看来要么实现不正确,要么cplusplus.com不正确(“输出位置从文件末尾开始。”)和 cppreference.com不明确(“打开后立即寻找流的末尾”:哪个流?​​)。

显然有一个简单的解决方法:只需使用 stream.seekp(0, std::ios_base::end)

所以我的问题是:我的代码不正确吗?执行不正确?引用站点是否不正确?任何见解将不胜感激。

最佳答案

从N4296 [filebuf.members]中的下图可以看出

file io

组合 binary | out 将在 "wb"stdio 中打开文件,它将截断为零长度或创建用于写入的二进制文件(N1570 7.21.5.2)。

对于 ofstream 来说听起来有悖常理,如果您不希望文件被截断,则需要添加 in 标志,或者 app 如果您想避免截断并在每次写入时查找文件末尾。

额外提示:与 fstream 不同,ifstreamofstream 将自动或 std::ios_base::instd::ios_base::out 分别带有您提供给构造函数或 open 的任何标志。您还可以使用对象本身来访问标志:

std::ofstream check("test", check.in | check.binary | check.ate);

good 的检查也可以简化为 if (!initial)

关于c++ - 带有 std::ate 的 std::ofstream 未在末尾打开,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28999745/

相关文章:

c++ - 如何与调试器交谈,或更改异常消息?

c++ - 展开不同长度的参数包

c++ - 如何在不清除文件的情况下使用 ofstream 多次写入文件?

c++ - 使用 ios::Nocreate 标志会导致 "undeclared identifier"错误

C++ If语句将不起作用

c++ - 将 OpenCV 灰度 Mat 转换为 Caffe blob

c++ - 为什么我的派生类找不到我的基类的类型别名?

c++ - Std::copy 和 std::ostream_iterator 使用重载函数打印值

c++ - tellg() 仅对小文件返回 -1

c++ - 避免被无符号整数除法签名