C++如何检测文件已被当前进程打开 满足日志追加开发需求
C++ 多位置复用日志文件输出实现问题
需求背景
我需要实现一个日志工具,可根据用户配置从代码的不同位置输出到相同或不同文件:若文件未打开则新建日志文件,若已打开则直接向文件追加内容。
使用如下原生写法会抢占文件流并重建文件:
std::ofstream f1("log"); f1 << "1 from f1\n"; std::ofstream f2("log"); f2 << "1 from f2\n"; f1 << "2 from f1\n";
该写法运行后日志仅保留1 from f2内容。若使用append模式打开,虽能复用文件但第二次打开会抢占f1的流,最终日志仅存在前两行写入内容,f1的后续写入会丢失。
现有方案缺陷
- 提前预判所有要用到的日志文件并在程序启动时全部打开:方案可行,但会创建大量实际未使用的文件
- 每次写日志都临时以追加模式打开、写完就关闭:可实现需求,但会产生大量系统调用和刷盘操作,性能过低
我打算自己维护一个已打开文件的静态表,期望用std::filesystem::canonical处理路径适配全场景,但我理解这类已打开文件映射表本就应该存在于进程的某处。我了解Fortran可以用inquire语句检测文件是否已打开,也查阅了相关问题,但没有找到C/C++下的实现方案。
内容更新
我基于静态已打开文件表实现了一个简易日志工具,代码如下:
//hpp class Logger { static std::mutex _mutex; static std::unordered_map<std::string, std::ofstream> _openFiles; std::ostream& _appender; std::ostream& _createAppender(const std::filesystem::path& logPath); public: Logger(const std::filesystem::path& logPath): _appender(_createAppender(logPath)) { } template<class... Args> void log(const Args&... args) const { std::scoped_lock<std::mutex> lock(_mutex); (_appender << ... << args); } };
//cpp #include "Logger.hpp" std::mutex Logger::_mutex; std::unordered_map<std::string, std::ofstream> Logger::_openFiles; std::ostream& Logger::_createAppender(const std::filesystem::path& logPath) { if (logPath.empty()) return std::cout; const auto truePath{std::filesystem::weakly_canonical(logPath).string()}; std::scoped_lock<std::mutex> lock(_mutex); const auto entry{_openFiles.find(truePath)}; if (entry != _openFiles.end()) return entry->second; _openFiles.emplace(truePath, logPath); std::ostream& stream{_openFiles[truePath]}; stream.exceptions(std::ifstream::failbit|std::ifstream::badbit); return stream; }
该实现或许可以帮到有相同需求的人。但我还是想知道是否可以直接从系统获取提到的句柄/描述符映射表,如果有人能说明如何在程序内实现该功能,我会采纳对应答案。
内容的提问来源于stack exchange,提问作者Askold Ilvento
相关产品推荐
相关产品推荐

