C++17中如何使用iostream/fstream实现带O_EXCL标志的线程安全文件创建?
C++17下实现仅当文件不存在时原子创建文件的fstream方案
C++17标准没有为std::fstream/std::ofstream定义官方的O_EXCL对应打开模式,但有两种常用的实现方案可以达到和open(O_WRONLY|O_CREAT|O_EXCL)完全一致的原子创建效果。
方案1:使用主流标准库的扩展标志
绝大多数主流C标准库实现(GCC libstdc、Clang libc++、MSVC STL)都提供了非标准的std::ios::excl打开标志,和O_EXCL行为完全一致,使用方式非常简单:
#include <fstream> // ... std::ofstream out_file("test.txt", std::ios::out | std::ios::excl); if (out_file.is_open()) { // 文件不存在,原子创建成功,可以正常写入 out_file << "write content" << std::endl; } else { // 文件已存在或其他IO错误,创建失败 }
注意:该标志属于实现扩展,不属于C++17强制标准要求,如果需要兼容所有标准库实现,建议使用方案2。
方案2:混用C系统调用与fstream(标准兼容、原子性保证)
这个方案完全符合C++17标准要求,并且100%还原open调用的原子性:先通过open系统调用按要求拿到原子创建后的文件描述符,再将其关联到std::ofstream使用:
#include <fstream> #include <cstdio> // POSIX系统头文件,Windows下替换为<io.h>和<fcntl.h> #include <fcntl.h> #include <unistd.h> #include <sys/stat.h> // ... int fd = open("target_output.txt", O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) { // 可通过errno判断是文件已存在还是其他IO错误 perror("create file failed"); // 错误处理逻辑 } FILE* c_file = fdopen(fd, "w"); if (!c_file) { close(fd); perror("associate fd to FILE* failed"); // 错误处理逻辑 } // 关联到C++ ofstream,后续可以正常使用流式接口 std::ofstream out_stream(c_file); // 写入示例 out_stream << "test content" << std::endl; // 流销毁时会自动关闭底层FILE*和文件描述符,无需手动调用close
禁用方案:先判断文件存在再创建
不要通过std::filesystem::exists先判断文件是否存在、再调用普通ofstream::open创建文件,这个操作是非原子的,多线程/多进程同时操作时会出现竞态,无法保证仅创建一次的要求。
内容的提问来源于stack exchange,提问作者vy32
相关产品推荐
相关产品推荐

