如何打开一个文件进行读写操作,如果文件不存在则创建它,但不截断它?

15

如果我想要读写文件,而且不想截断已存在的文件,但是如果文件不存在则创建它,那么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对象,然后立即关闭它并打开我真正想要的流,但如果可以用单个流对象避免这种情况,则会显得混乱。

3个回答

4
在这种情况下,我得出结论,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++11及更高版本中不需要使用c_str()。如果Boost文件系统可以为您完成此操作(我不确定),那么您只需等待到C++17。;-) - Cheers and hth. - Alf
@Cheersandhth.-Alf 标记(c++03),似乎 c_str() 的原因是,尽管如果任何人阅读此内容并使用 C++11 或更高版本,则显然是正确的。顺便问一下,03x 中是否包括了 std::string 构造函数? - WhozCraig
@WhozCraig:不,C++03 中唯一的新东西就是值初始化。 - Cheers and hth. - Alf
@Cheersandhth.-Alf 啊..那么所有这些 c_str 确实在与该标记配对时有意义。感谢您提供的信息! - WhozCraig
@Cheersandhth.-Alf:我意识到我不 需要 检查第一个流,但如果创建文件失败,我宁愿有更具体的错误消息。而且,是的,因为是C++03版本所以需要.c_str()。 :) - Lightness Races in Orbit
1
@Lightness Races in Orbit,我认为你在调用std::ostream构造函数时忘记添加std::ios::binary | std::ios::app了。如果没有这些标志,文件将被截断,如果它已经存在,这是你说过不想要的事情。当我偶然发现这个问题时,我也不想要这种情况 :) - user1593842

3
从Linux的角度来看(尽管这很可能适用于其他Unix系统):
在系统调用层面,您需要使用open(O_RDWR | O_CREAT, 0666)(但不要使用O_TRUNCO_APPEND或一堆其他标志,尽管可以认为所有文件都应该使用O_CLOEXEC | O_LARGEFILE打开,但这并不重要)。
在libc层面,没有标准的mode字符串能够隐含O_CREAT而不带有O_TRUNC。但是,您可以使用open后跟fdopen
在C++库级别上,没有标准的方法来传递所需的标志。但是,使用特定于实现的类/函数或第三方库是可能的;请参见如何从POSIX文件描述符构建c++ fstream?
个人而言,我倾向于在C甚至系统调用级别上执行所有I/O操作,因为API更好,更可预测。对于类实例的输入/输出,我使用自己的模板。

-1

假设您已经了解了 std::ios::binary,那么您可能需要的其余 openmode 是:

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

它的效果就像使用以下方式打开文件:

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

的效果是:

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

如果您将文件作为std::fstream使用此openmode打开,则不会截断该文件(如果存在)。您可以从fstreamtellg()\tellp()指针指向的任何位置读取文件,前提是有可读取的内容,并且您可以使用流的seekg()\seekp()定位该指针进行读取。但是,所有写入都将附加到文件末尾。

因此,除非您需要对现有数据执行写操作,否则此openmode将符合您的要求。


谢谢,接近了,但是:“我不想使用std::ios::app,因为我还需要能够随意在文件中寻找,使用get和put光标。” - Lightness Races in Orbit

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