.trail文件里到底存了什么?Cartographist会话保存、加载与md5脏检测设计深度剖析
2026/8/25 17:45:36 网站建设 项目流程

.trail文件里到底存了什么?Cartographist会话保存、加载与md5脏检测设计深度剖析

【免费下载链接】cartographistexperimental web browser optimized for rabbit-holing项目地址: https://gitcode.com/gh_mirrors/ca/cartographist

Cartographist 是一个面向"深度研究式浏览"(rabbit-holing)的实验性 Web 浏览器,它最独特的能力是:把整个浏览会话保存成.trail文件,下次一键加载即可完整复原。这篇文章带你深入源码,拆解.trail文件里到底存了什么、保存/加载是如何实现的,以及那个精妙的md5 脏检测是怎么判断"你有没有未保存的修改"的。

.trail 文件是什么?本质是一行 JSON

.trail文件没有任何特殊格式,就是应用内部状态对象stateJSON.stringify结果。整个应用的状态由三个字段组成,定义在src/renderer/index.jscreateEmptyState中:

字段类型含义
history整棵浏览历史树(最核心的数据)
panes数组当前打开的窗格 URL 列表,决定加载后哪些页面会重新打开
fullscreenId数字/null哪个窗格处于全屏

也就是说,加载一个.trail文件后,你回到的是离开那一刻的精确现场:同样的历史树、同样的窗格、同样的全屏状态。

核心数据结构:浏览历史树

history是一棵树,每个节点长这样(由src/renderer/history.jscreate函数创建):

  • url:页面地址
  • title:页面标题(页面加载后由 webview 回填)
  • children:子节点数组
  • timestamp:创建时间戳

关键在于它不是线性历史:每次从 A 导航到 B,就在 A 节点下挂一个 B 子节点;同一路径重复访问则直接复用已有节点(navigate函数里的去重逻辑)。于是"研究某个话题时岔出去又折返"的完整路径被保留下来,左侧的树状大纲(src/renderer/history-visualization.js)就是这棵树的可视化。这也是.trail文件体积会随着研究深入而增长的原因。

保存流程:Save Trail 三步走

菜单里选择Save Trail(快捷键 Cmd/Ctrl+S,定义在src/main/menu.js)后,src/renderer/index.js中的SAVE_TRAIL监听器做三件事:

  1. 弹出系统保存对话框,默认文件名为cartographist.trail
  2. JSON.stringify(state)序列化当前状态
  3. setLastStoreHash(md5(stringified))—— 记录这次内容的 md5 哈希
  4. fs.writeFileSync写入文件

第 3 步是整个脏检测设计的起点:应用从此记住了"我最后持久化的那份内容长什么样"。

加载流程:Load Trail 的容错细节

Load Trail(Cmd/Ctrl+O)流程:

  1. 打开文件对话框,过滤器限定扩展名为trail
  2. fs.readFileSync+JSON.parse,解析失败会弹出错误提示
  3. 成功后先setLastStoreHash(md5(data)),再整体替换状态

注意加载时哈希是对文件原始字节取的 md5,而保存时是对JSON.stringify结果取的——正因为保存写入的就是这份字符串,两者天然对齐,脏检测才能闭环。

md5 脏检测:如何知道"有未保存修改"?

这是设计里最优雅的部分。应用用一个 React 状态lastStoreHash保存"基准哈希",当用户点击New Trail(Cmd/Ctrl+N,想放弃当前会话从头开始)时:

  1. 计算当前状态的实时哈希:md5(JSON.stringify(state))
  2. lastStoreHash比较
  3. 不相等→ 说明自上次保存/加载以来状态发生过变化,弹出警告:"当前 trail 有未保存的修改,继续将丢失,是否继续?"
  4. 相等→ 无变化,静默重置到初始状态

为什么不直接比较对象?因为state是嵌套很深的树加数组,深度比较成本高且易错;而 md5 把任意大小的状态压缩成一个固定指纹,一次字符串比较即可。代价是它只能回答"变没变",无法回答"哪里变了"——对脏检测来说,这恰恰是足够且廉价的方案。

隐藏的第三层持久化:localStorage 自动恢复

除了手动的.trail文件,Cartographist 还有一条"无感"的保存通道:src/renderer/use-persisted-immer.js这个自定义 Hook 会把每次状态变更都写入localStorage["state"],应用重启后自动读取恢复。

三层持久化各司其职:

  • localStorage:崩溃/重启后的自动恢复,用户无感知
  • Save Trail:主动归档一次研究现场,可长期保存、跨设备携带
  • md5 脏检测:在"新会话"和"旧现场"之间为用户守住数据安全

小结

.trail文件的本质 = 一棵带时间戳的浏览树 + 窗格列表 + 全屏状态,一行 JSON 即完整会话。而lastStoreHash这一个 md5 指纹,用最小代价实现了"未保存修改"的可靠提示。这套"树状历史 + 指纹比对"的设计,对任何需要会话快照的工具(浏览器、IDE、爬虫管理器等)都有不错的借鉴价值。想动手验证的话,直接看src/renderer/index.js中三个 IPC 监听器的实现即可,代码量不到 70 行。

【免费下载链接】cartographistexperimental web browser optimized for rabbit-holing项目地址: https://gitcode.com/gh_mirrors/ca/cartographist

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询