如何打开一个文件进行读写,如果它不存在则创建它而不截断它?
How can I open a file for reading & writing, creating it if it does not exist, without truncating it?
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
,因为我还需要能够随意搜索文件,同时使用 get 和 put个游标。
我想,一个解决方法是先实例化一个 std::ofstream
,然后立即关闭它并打开我真正想要的流,但如果可以用单个流对象避免它,那似乎很麻烦。
目前,我的结论是 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`
以std::ios::binary
为读,剩下的openmode
可能是你需要的:
std::ios::in | std::ios::app
它的效果就像打开文件一样:
std::fopen(filename,"a+")
而那个的效果是:
- 打开或者如果不存在则创建文件进行读写
- 在文件末尾写入数据。
如果您使用此 openmode
打开文件作为 std::fstream
,如果它存在则不会被截断。你可以
从 fstream
的 tellg()\tellp()
指针指向的文件中读取,
前提是那里有东西要读,你可以定位那个指针
使用流的 seekg()\seekp()
进行阅读。但是,所有写入都将
附加到文件末尾。
除非您需要执行写入,否则此打开模式将符合您的要求
到现有数据中。
一项调查,从 Linux 的角度来看(尽管其中大部分可能适用于其他 Unices):
在系统调用层,你想要 open(O_RDWR | O_CREAT, 0666)
(但不是 O_TRUNC
或 O_APPEND
或一堆其他标志,尽管可以说所有文件都应该用 O_CLOEXEC | O_LARGEFILE
, 但那不是重点)
在 libc 层,没有标准的 mode
字符串暗示 O_CREAT
没有 O_TRUNC
。但是,您可以使用 open
后跟 fdopen
.
在 C++ 库级别,没有传递所需标志的标准方法。但是,使用特定于实现的 classes/functions 或第三方库是可能的;见 How to construct a c++ fstream from a POSIX file descriptor?
就个人而言,我倾向于在 C 甚至系统调用级别执行所有 I/O,因为 API 更好并且更可预测。对于 class 个实例中的 input/output 个,我有自己的模板。
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
,因为我还需要能够随意搜索文件,同时使用 get 和 put个游标。
我想,一个解决方法是先实例化一个 std::ofstream
,然后立即关闭它并打开我真正想要的流,但如果可以用单个流对象避免它,那似乎很麻烦。
目前,我的结论是 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`
以std::ios::binary
为读,剩下的openmode
可能是你需要的:
std::ios::in | std::ios::app
它的效果就像打开文件一样:
std::fopen(filename,"a+")
而那个的效果是:
- 打开或者如果不存在则创建文件进行读写
- 在文件末尾写入数据。
如果您使用此 openmode
打开文件作为 std::fstream
,如果它存在则不会被截断。你可以
从 fstream
的 tellg()\tellp()
指针指向的文件中读取,
前提是那里有东西要读,你可以定位那个指针
使用流的 seekg()\seekp()
进行阅读。但是,所有写入都将
附加到文件末尾。
除非您需要执行写入,否则此打开模式将符合您的要求 到现有数据中。
一项调查,从 Linux 的角度来看(尽管其中大部分可能适用于其他 Unices):
在系统调用层,你想要 open(O_RDWR | O_CREAT, 0666)
(但不是 O_TRUNC
或 O_APPEND
或一堆其他标志,尽管可以说所有文件都应该用 O_CLOEXEC | O_LARGEFILE
, 但那不是重点)
在 libc 层,没有标准的 mode
字符串暗示 O_CREAT
没有 O_TRUNC
。但是,您可以使用 open
后跟 fdopen
.
在 C++ 库级别,没有传递所需标志的标准方法。但是,使用特定于实现的 classes/functions 或第三方库是可能的;见 How to construct a c++ fstream from a POSIX file descriptor?
就个人而言,我倾向于在 C 甚至系统调用级别执行所有 I/O,因为 API 更好并且更可预测。对于 class 个实例中的 input/output 个,我有自己的模板。