Task Tracker Cli项目学习日志
原文链接:https://www.cnblogs.com/Time25/p/19828921.html
2026.4.7
开始Task_Tracker_Cli的工作:开始的目的主要是为了实现一个可以自动管理任务的小工具,可以应用到自己的生活中
学习点1:输入文件流对象,在函数loadTasks()中
学习原因是因为在代码中发现
1 std::ifstream file(FILE_NAME);
代码在项目中的详细意思是:
std::ifstream 是 C++ 标准库中的类,用于创建输入文件流对象,从文件读取数据。
file(FILE_NAME) 创建一个名为 file 的 std::ifstream 对象,并尝试以只读模式打开名为 FILE_NAME(常量字符串 “tasks.json”)的文件。
如果文件存在且可访问,file 对象可用于后续读取操作;如果失败,file.is_open() 将返回 false(下一行代码会检查并处理)。
在 loadTasks 函数上下文中,这行代码用于打开任务数据文件,为后续从 JSON 文件加载任务列表做准备。
形象比喻
- 核心比喻:数据水管
想象一下:
你的硬盘上的 tasks.json 文件:是一个装满水的水库(水就是文件里的文本数据)。
你的 C++ 运行程序(内存):是一个空水桶,现在急需把文件里的数据装进来处理。
水库里的水不可能瞬间“瞬移”到水桶里。你需要买一根水管,一头插进水库,一头放在水桶里,让水一点点流(Stream)过来。
在 C++ 里:
流(Stream):指的就是数据像流水一样,一滴一滴(一个字节一个字节)地传输。
输入(Input):站在程序的视角,数据从外面(硬盘)进到程序里,叫输入。
对象(Object):就是你在代码里造出来的这根“水管”的实体。
所以,输入文件流对象,就是C++专门用来从硬盘文件里“往程序里抽水(读数据)”的那根管子。它的英文真名叫做 ifstream (Input File Stream)。
个人理解:
创建了一个名字叫做:file的对象,可以把这个对象理解为一个水管,这个水管是插入到FILE_NAME这个里面的(也就是tasks.json),学习点2:既然有输入文件流,就有输出文件流
同理,这个就是在task.json文件中加数据(往硬盘里的文件里喷数据。),类似的东西就是cout<<”hello world”;,这不过这个是在屏幕上喷东西,1
std::ofstream file(FILE_NAME);
学习代码一些小细节1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30void saveTasks(const std::vector<Task>& tasks) {
// 1. 【架起喷枪】
// 创建对象,管子一头插进硬盘的 tasks.json
std::ofstream file(FILE_NAME);
// 2. 【清空底色】
// 默认情况下,ofstream 一打开文件,就会把文件里原来的内容全部擦干净!
// 就像你要重新刷墙,它先帮你把旧墙纸撕了。
// 3. 【开始喷涂】
file << "[\n"; // 往文件里喷一个方括号,代表 JSON 数组开始
for (size_t i = 0; i < tasks.size(); ++i) {
// 接下来这一大段,就是按照特定的格式一点点往文件里“喷”文字
file << " {\n";
file << " \"id\": " << tasks[i].id << ",\n";
file << " \"description\": \"" << tasks[i].description << "\",\n";
file << " \"status\": \"" << tasks[i].status << "\"\n";
file << " }";
// 如果不是最后一个任务,喷个逗号隔开
if (i < tasks.size() - 1) file << ",";
file << "\n";
}
file << "]\n"; // 喷完收工,闭合方括号
// 4. 【放下喷枪】
// 函数结束,file 对象销毁,自动关闭文件,确保水滴不漏,所有数据安全写入硬盘。
}既然输出流有一个缓冲区,那么输入流就肯定也有,接下来是具体操作流程1
2
3
4
5
6
7
8
9
10
11A. 为什么不用手动关文件?
你可能会看到有些老代码写 file.close();。但在现代 C++ 里,只要 file 这个变量的作用域(那对大括号 {})结束了,它会自动执行析构函数,帮你把文件关得严严实实。这叫“负责任的资源管理”。
B. 万一我想“接着喷”而不是“覆盖喷”怎么办?
默认情况下,ofstream 是覆盖模式。如果你想在文件末尾接着写,不删掉以前的内容,你需要加一个参数(追加模式):
code
C++
std::ofstream file(FILE_NAME, std::ios::app); // app 就是 append(追加)
但是在我们的任务管理器里,我们是把整个列表改好了再一次性覆盖写入,所以不用加这个参数。
C. 它是先喷到“缓冲区”的
这把喷枪其实不是直接喷到硬盘上的(因为硬盘很慢)。它是先喷到内存里的一个“缓存桶”里。等桶满了,或者程序结束了,系统才会哗啦一下全部倒进硬盘。这样效率更高。
就类似于:你要吃一个糖果就去买一颗,等会要吃了就又去买一颗,这有太浪费时间了,更高效的做法是一次性就买100颗 - 输入流的工作流程(以你的 loadTasks 为例)
当你执行 buffer << file.rdbuf(); 或者读取文件内容时,幕后发生了这些事:
预读(Read-ahead):
当你让 file 去读 1 个字节时,操作系统其实并不只读这 1 个字节。它会“自作聪明”地从硬盘里直接搬一大块数据(比如 4KB 或 8KB)出来,塞进内存里的输入缓冲区。
内存取货:
接下来的读取操作(比如你想找下一个引号、下一个逗号),程序其实根本没去碰硬盘,而是直接在内存里的缓冲区里“翻找”。这速度快得飞起!
自动补货:
当缓冲区里的数据被你读光了,而文件还没读完,系统会自动再去硬盘里搬下一块数据进来填满“储水罐”。
进阶
如果你想强制“清空”缓冲区?
对于输出流:有时候你写了数据,但还没攒够一桶,它没写进硬盘。如果你急着要看,可以用 file << std::endl; 或者 file.flush();。这就像是强行踩一下马桶冲水键,不管桶里有多少,全部冲进硬盘。
对于输入流:通常不需要手动干预,它会自动预读。学习点3:把文件内容读入到字符串流中
这个类似于一个巨大容器,把你从硬盘里读到的东西都加入到这个里面,后续你要借助这个把你读取的东西变成一个长的字符串,就是借助下面这个:1
std::stringstream buffer;
1
buffer.str();
// TRAINING LOG · 第 45 / 76 篇训练记录 · 成文于 2026.04.07 · 正午 11:03
本文是原创文章,采用CC BY-NC-SA 4.0许可协议,完整转载请注明来自FMAN720 / ALGO LOG
