第 14 章:文件与异步日志
本章说明路径工具、线程安全文件对象、有界异步日志及其生命周期关系。
1. 三层能力
| 类 | 职责 | 关键契约 |
|---|---|---|
FileTool | 创建目录/文件、二进制复制、获取大小 | copy() 不创建目标父目录;任一文件打开或写入失败返回 false |
File | 线程安全文本/二进制读写和内存事务 | 文件操作从 openFile() 开始;内存事务由加锁线程解锁 |
LogFile | 有界队列和独立消费者线程 | 队列满时丢弃并计数,不阻塞业务线程 |
2. 文件复制保留原始字节
if(!stt::file::FileTool::copy(
"runtime/source.bin",
"runtime/backup/source.bin"))
{
// 目标父目录不存在、文件打不开或写入失败。
}copy() 按二进制复制,NUL、换行和不可打印字节都会保留。目标父目录需在调用前存在。
3. File 与内存事务
stt::file::File config;
if(!config.openFile("runtime/app.conf"))
return 1;
config.deleteAll();
config.appendLine("port=8080");
config.appendLine("workers=4");
config.closeFile();普通方法自行完成锁定、修改和保存。lockMemory() 与带 C 后缀的方法表示同一把锁内的多步事务;每条退出路径都与一次 unlockMemory() 对应。
4. 异步日志的生命周期
{
// 容量采用 MPSCQueue 要求的 2 的幂。
stt::file::LogFile log(16384);
if(!log.openFile("logs/server.log", ISO8086B, " "))
return 1;
log.writeLog("server started");
std::cout << log.getDroppedLogCount() << '
';
// 所有生产者停止后,作用域结束时由析构流程排空队列。
// 析构函数会停止消费者并排空已经进入队列的日志。
}- 固定时长的
sleep(50ms)不能作为日志刷盘完成的判断依据。 LogFile的生命周期需要覆盖所有调用writeLog()的线程。- 队列满时写入会被丢弃;通过
getDroppedLogCount()监控。 deleteLogByTime(start,end)使用[start,end)区间。- 日志内容应排除密码、私钥、完整 Token/Cookie 和敏感请求体。