c++如何实现文件访问次数的持久化统计功能【进阶】

风杰酱_1106

风杰酱_1106

2026-04-11

261人浏览

原创

fopen+计数器无法持久化,因缺乏原子性更新与崩溃容错:先读再写易因中断丢失数据,无锁并发会覆盖,纯文本无校验;推荐原子重命名+json方案。

c++如何实现文件访问次数的持久化统计功能【进阶】

为什么 fopen + 计数器无法持久化?

直接在程序里用全局变量或静态变量累加访问次数,进程退出就清零。哪怕用 std::ofstream 每次打开写一次,也容易因异常、崩溃或并发导致计数丢失或错乱。持久化核心是「原子性更新」和「落地可靠」,不是“写进去就行”。

  • 单次写入不加锁 → 多进程同时访问同一文件会覆盖彼此的计数
  • 先读再写再保存 → 中间崩溃(如断电)会导致旧值丢失、新值未写入
  • 用普通文本格式存数字 → 没有校验,文件被手动改写后程序无法识别

推荐方案:用原子重命名 + JSON 格式存储

Linux/macOS 下利用 rename() 的原子性,Windows 下用 MoveFileEx 配合 MOVEFILE_REPLACE_EXISTING。JSON 便于人工检查、支持扩展字段(如最后访问时间、IP等),且 nlohmann/json 库解析轻量、无依赖。

  • 每次访问前,读取当前 stats.json(若不存在则初始化为 {"count":0,"updated":"..."})
  • 内存中递增 count,更新 updated 字段为当前时间戳
  • 将新内容写入临时文件 stats.json.tmp
  • 调用 rename("stats.json.tmp", "stats.json") —— 这步是原子的,失败则保留原文件

示例关键逻辑(C++20,需链接 -lnlohmann_json):

C++ Code Review Master
C++ Code Review Master

组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。

下载
#include <nlohmann>
#include <fstream>
#include <filesystem>

int update_access_count(const std::string& path) {
    nlohmann::json j;
    std::ifstream f(path);
    if (f.good()) j = nlohmann::json::parse(f, nullptr, false);
    if (j.is_discarded()) j = {{"count", 0}};
    j["count"] = j.value("count", 0) + 1;
    j["updated"] = std::time(nullptr);

    std::string tmp_path = path + ".tmp";
    std::ofstream out(tmp_path);
    out ();
}
</filesystem></fstream></nlohmann>

Windows 下 CreateFile 的共享模式陷阱

如果用 CreateFile 手动控制文件句柄,必须显式设置 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE,否则其他进程(包括自己下次启动)会因“文件正被另一进程使用”而打不开 —— 这会导致统计中断,而非并发冲突。

  • 只设 FILE_SHARE_READ → 写入新统计时被拒绝
  • 完全不设共享模式(默认 0)→ 第二次运行直接 INVALID_HANDLE_VALUE
  • 即使用了原子重命名,也要确保读取原 stats.json 时允许被其他进程同时读

并发安全的底线:不要依赖 flock 或 LockFile

flock 在 NFS 或某些容器环境不可靠;LockFile 是字节范围锁,对整个文件加锁又太重,且 Windows 上跨进程 lock 可能不释放干净。真正的容错做法是:接受偶尔的计数偏差(比如两次并发访问只记成 +1),但保证「不丢数据」「不损坏格式」「不阻塞主流程」。

  • 把统计更新设为 fire-and-forget:异步线程做,失败就丢弃日志,不影响业务
  • 定期(如每天)用脚本校验 stats.json 是否为合法 JSON,防止被篡改后程序 crash
  • 如果要求强一致性(如计费场景),就得换数据库,文件系统本身不提供事务语义

最常被忽略的是:没给 stats.json 设置合适的目录权限(尤其多用户环境),导致非属主进程无法写入 —— 这比并发问题更早出现,且错误静默。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

2023.08.07

2015

5

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.23

2862

1

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

2023.10.13

976

3

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

2025.09.10

3219

7

counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.11.20

2648

5

全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

2025.09.18

3985

12

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

2025.09.18

1630

13

c++ 全局变量
c++ 全局变量

本专题整合了c++全局变量的使用、定义、作用域等等内容,阅读专题下面的文章了解更多详细内容。

2026.03.17

199

17

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

2023.08.10

3738

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Conan 2 Essentials 免费课程
Conan 2 Essentials 免费课程

共0课时 | 0人学习

CMake 与 Conan 集成实践
CMake 与 Conan 集成实践

共0课时 | 0人学习

Conan 2 高级依赖模型介绍
Conan 2 高级依赖模型介绍

共0课时 | 0人学习