std::ofstream 直接写文件不适合做日志系统,因其频繁i/o性能差、多线程不安全、缺乏时间戳和级别标识;可靠方案需支持线程安全、异步/缓冲写入、格式化、级别控制与自动轮转,推荐用spdlog。

为什么 std::ofstream 直接写文件不适合做日志系统
直接用 std::ofstream 每次 open() → write() → close(),会触发频繁磁盘 I/O,性能差;多线程下不加锁会乱序甚至崩溃;没时间戳、级别标识,查问题时根本分不清哪条是 ERROR 哪条是 DEBUG。真正能用的日志系统,至少得支持:线程安全、异步写入(或缓冲)、格式化输出、级别控制、自动轮转。
用 spdlog 三行接入,避免自己造轮子
自己写带缓冲、线程安全、支持滚动的文件日志,两周都调不完。spdlog 是 C++ 里最轻量又可靠的日志库,头文件即用,无需编译依赖(启用 SPDLOG_COMPILED_LIB 才需链接)。实战中推荐这样初始化:
#include <spdlog/spdlog.h>
#include <spdlog/sinks/rotating_file_sink.h>
<p>auto logger = spdlog::rotating_logger_mt("file_logger", "app.log", 1048576 * 5, 3);
logger->set_level(spdlog::level::debug);
logger->info("startup ok");
说明:rotating_logger_mt 表示多线程安全 + 自动轮转;参数 "app.log" 是基础文件名,1048576 * 5 是单文件上限(5MB),3 是最多保留 3 个历史文件(app.log.1, app.log.2…)。
不用第三方库?手写最小可行日志类要注意什么
如果项目限制不能引入外部依赖,可封装一个极简线程安全文件日志类,但必须守住三条底线:
立即学习“C++免费学习笔记(深入)”;
- 用
std::mutex锁住write()全过程,而不是只锁std::ofstream::write()—— 否则格式化字符串拼接(如std::to_string())可能被并发打断 - 不要每次写都
open()/close(),而应复用std::ofstream对象,并在构造时用std::ios::app模式打开,否则日志会被覆盖 - 手动添加时间戳需用
std::chrono+std::put_time,避免ctime()返回静态缓冲区(多线程下会冲突)
关键片段示例(仅核心逻辑):
class SimpleFileLogger {
std::ofstream file_;
mutable std::mutex mtx_;
public:
SimpleFileLogger(const char* path) : file_(path, std::ios::app) {}
void log(const char* level, const char* msg) const {
std::lock_guard<std::mutex> lk(mtx_);
auto now = std::chrono::system_clock::now();
auto time_t = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
ss << std::put_time(std::localtime(&time_t), "%Y-%m-%d %H:%M:%S")
<< " [" << level << "] " << msg << "
";
file_ << ss.str();
file_.flush(); // 确保立即落盘,否则可能卡在缓冲区
}
};
日志输出到文件却看不到内容?检查这三点
常见“写了日志但文件空”或“只有第一条”的问题,基本集中在:
-
std::ofstream构造失败没检查:if (!file_.is_open()) { /* 报错 */ },路径不存在或权限不足时静默失败 - 忘记调用
flush()或close(),尤其程序异常退出时,缓冲区内容直接丢失 - Windows 下路径用了反斜杠
"C:logspp.log",未转义成"C:\logs\app.log"或用原始字符串R"(C:logspp.log)",导致路径解析错误
真实项目里,日志系统的健壮性往往体现在这些细节上——不是功能多炫,而是崩了还能留下最后一句错误。











