【问题标题】:How can I open a file for reading & writing, creating it if it does not exist, without truncating it?如何打开一个文件进行读写,如果它不存在就创建它,而不截断它?
【发布时间】:2015-10-07 14:51:28
【问题描述】:

std::fstream 的正确 I/O 标志集是什么,我希望能够从 读取并 写入文件,而不截断文件(如果存在),但是如果没有,创建它?

我试过了

std::ios::binary | std::ios::in | std::ios::out
std::ios::binary | std::ios::in | std::ios::out | std::ios::ate

但如果文件不存在,它们都不会创建文件。

我不想要std::ios::app,因为我还需要能够使用 getput 光标随意搜索文件。

我想,一种解决方法是先实例化一个 std::ofstream,然后立即关闭它并打开我真正想要的流,但如果可以使用单个流对象来避免它,这似乎很混乱。

【问题讨论】:

    标签: c++ iostream fstream c++03


    【解决方案1】:

    目前,我的结论是 std::ios::in 完全可以防止这种情况发生,我必须使用解决方法。

    所以:

    if (!std::ostream(path.c_str()))
       throw std::runtime_error("Could not create/open file");
    
    std::fstream fs(path.c_str(), std::ios::binary | std::ios::in | std::ios::out);
    if (!fs)
       throw std::runtime_error("Could not open file");
    
    // ... use `fs`
    

    【讨论】:

    • 创建尝试不需要失败检查或报告。另外,我认为您不需要将 c_str() 与 C++11 及更高版本一起使用。 Boost 文件系统可能会为你做这件事(我不知道),如果是这样,那么你只需要等到 C++17。 ;-)
    • @Cheersandhth.-Alf as-tagged (c++03),似乎是 c_str() 的原因,尽管如果有人读到这篇文章会用 C+ 来做,那么你显然是对的+11 或更高版本。顺便说一句,std::string 构造不是包含在 03x 中吗?
    • @WhozCraig:不,C++03 中唯一的新功能是值初始化。
    • @Cheersandhth.-Alf 啊..那么所有c_str 与该标签结合时确实有意义。感谢您的信息!
    • @Lightness Races in Orbit,我相信您在调用std::ostream 构造函数时忘记添加std::ios::binary | std::ios::app。如果没有这些标志,文件将被截断以防它已经存在,这是你说你不想要的。当我偶然发现这个时我也没有:)
    【解决方案2】:

    从 Linux 的角度进行的一项调查(尽管其中大部分可能适用于其他 Unices):

    在系统调用层,您需要open(O_RDWR | O_CREAT, 0666)(但不是O_TRUNCO_APPEND 或一堆其他标志,尽管可以说所有文件都应该用O_CLOEXEC | O_LARGEFILE 打开,但这不是重点)

    在 libc 层,没有标准的 mode 字符串暗示 O_CREAT 而没有 O_TRUNC。但是,您可以使用open,后跟fdopen

    在 C++ 库级别,没有传递所需标志的标准方法。但是,使用特定于实现的类/函数或第三方库,这是可能的;见How to construct a c++ fstream from a POSIX file descriptor?


    就我个人而言,我倾向于在 C 甚至系统调用级别执行所有 I/O,因为 API 更好并且更可预测。对于类实例的输入/输出,我有自己的模板。

    【讨论】:

      【解决方案3】:

      std::ios::binary为读,剩下的openmode可能你需要的是:

      std::ios::in | std::ios::app
      

      它的效果就像打开文件:

      std::fopen(filename,"a+")
      

      那个的效果是:

      • 打开,如果不存在,则创建文件进行读写
      • 在文件末尾写入数据。

      如果您使用此openmode 作为std::fstream 打开文件,则如果存在,则不会被截断。你可以 从文件中读取fstreamtellg()\tellp() 指针指向的任何位置, 只要那里有东西要读,你就可以定位那个指针 使用流的seekg()\seekp() 进行阅读。但是,所有写入都将 附加到文件末尾。

      因此,除非您需要执行写入,否则此开放模式将符合您的要求 到现有数据中。

      【讨论】:

      • 谢谢,关闭,但是:“我不想要std::ios::app,因为我还需要能够随意搜索文件,同时使用get 和put 游标。 "
      猜你喜欢
      • 2021-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-11
      • 2013-12-07
      • 2014-11-09
      • 2016-03-17
      • 2022-12-09
      相关资源
      最近更新 更多