Watch at Ease看见世界,读懂生活。

科技 · 实用指南

在 Linux 上创建文件历史记录的最新版本副本

在 Linux 上,从可读取的 Windows 文件历史记录文件夹中,按保存时的 UTC 时间选出各文件的最新版本,分别复制到新目录。

原创示意图展示 Work/report.pdf 的三个保存版本,按文件名中最新的 UTC 时间戳选出一个版本,使用可选的 --restore-names 设置另存为 Work/report.pdf。
原创说明示意图:从三个保存版本中选出最新一个。图中输出使用可选的 --restore-names;默认输出名称仍保留 UTC 时间戳。所有源版本继续留在备份中。 Watch at Ease

Windows 文件历史记录文件夹可能保存了同一文档的多个副本,每个副本的文件名都附有 UTC 时间戳。要为每个文件保留最新副本,需要按原目录和完整文件名将版本分组,再比较这些保存时间。不能用 Linux 列出文件的先后顺序代替时间比较。

下面的工具会另建一份仅含最新版本的副本。它不会改写或删除源文件,默认的预览操作也不会生成任何输出文件。执行复制时,工具会将选中的文件放进新输出目录;原备份中的旧版本仍然保留,它们占用的空间也不会因此释放。

先确认手头保存的是什么

首先需要一个可读取、实际包含已保存文件的文件夹。工具支持的文件名示例是 Report (2024_05_03 09_30_00 UTC).docx。同一目录中时间更晚的 Report (2024_05_08 16_15_00 UTC).docx 属于同一组。将工具指向你要处理的那部分目录树,不要因为一个文件夹叫 FileHistory,就认定里面的文件一定采用这种可见的命名格式。

保留完整的原备份。处理大量文件前,先查看几个文件,确认它们能打开。如果磁盘无法挂载、文件无法读取,或者文件名是不透明的标识符,就不应把这个工具当作下一步恢复手段。它无法根据文件历史记录的目录数据库重建原路径,也无法找回已经缺失的文件内容。

不要仅因名称相似,就把不同用户或不同电脑的备份合并到一个文件夹。选定实际要处理、能够读取的目录树,保留其中的目录结构,其他备份另行处理。这里的操作不能证明来自不同备份的两个同名文档就是同一个原文件。

了解工具会选中哪个版本

在同一目录内,工具会解析并比较同一个完整原文件名各版本所附的 UTC 时间戳。Report.docx 和 Report.pdf 分属两组;Documents/Report.docx 和 Archive/Report.docx 也分属两组。扩展名和目录都是区分文件的依据。

把文件复制到另一块磁盘,可能会改变文件系统记录的时间戳。工具不会按这些时间选择版本,也不会选择目录扫描中碰巧最后出现的那个版本:Python 文档说明,目录遍历得到的列表不一定有序。工具要选出的是每个受支持文件组中,实际存在的最大保存 UTC 时间值。

下载工具并确定路径

在 Linux 上打开终端,检查 Python 版本:

python3 --version

请使用 Python 3.10 或更高版本。将 filehistory-latest-v1.py 保存到一个工作文件夹,然后在该文件夹中打开终端。如果已安装 curl,可以用下面的命令下载源码文件。这条命令只保存脚本,不会运行它。

curl --fail --location "https://watchatease.com/guide-tools/filehistory-latest-v1.py" --output "filehistory-latest-v1.py"

下面的示例以 FileHistory-copy/Documents 作为源目录树,latest-documents 则是与 FileHistory-copy 并列的新输出文件夹。请将源路径替换为实际位置。路径含空格时要保留引号。输出目录必须尚不存在,而且源目录和输出目录不能重叠:不要把输出放进源目录里面。

复制前先预览选择结果

暂停所有会写入这部分源目录树的备份任务,并从预览开始到复制结束都避免改动其中的文件。这个过程不会在同一个瞬间捕获所有文件。先运行不带 --apply 的命令:

python3 "filehistory-latest-v1.py" --source "./FileHistory-copy/Documents" --output "./latest-documents"

工具会在终端显示 JSON 预览,不会创建输出目录。预览不读取文件内容,也不计算内容哈希,因此预览成功不代表之后一定能复制每个文件。继续前,请阅读路径和选择信息。检查一个有多个保存版本的熟悉文件、两个主文件名相同但扩展名不同的文件,以及不同目录中的同名文件。

不符合受支持时间戳格式的普通文件会被列为跳过项,不会复制进仅含最新版本的结果中。被跳过的文件仍可能很重要,请检查这些条目,按需要另行保留或复制;不要把输出当成源目录下全部内容的副本。

无效的 UTC 时间戳、符号链接、特殊文件或读取失败都会阻止本次操作。最新时间戳并列、无法明确选出一个版本时,也需要检查。应查明报告中路径对应的情况,不要为了通过检查而修改不熟悉的日期,或随意挑选一个并列文件。找不到任何受支持文件时也会阻止运行:请确认选中了包含带时间戳文件的数据目录树。

将最新版本复制到新目录

确认预览中的文件正是你要收集的内容后,在同一条命令末尾加上 --apply,再次运行:

python3 "filehistory-latest-v1.py" --source "./FileHistory-copy/Documents" --output "./latest-documents" --apply

输出包含 files 目录、manifest.csv 和 summary.json。选中的文件会保留相对目录结构。默认还会保留带保存时间戳的文件名,方便看出选中了哪个版本。原备份中的旧版本仍然存在。工具复制的是文件内容,不会复制原权限、ACL 或文件系统时间戳。

如果希望结果使用原文件名,可以加上 --restore-names。它只方便命名,不会改变哪个时间戳胜出。执行前,请换一个尚未使用的输出路径,先预览这一选项:

python3 "filehistory-latest-v1.py" --source "./FileHistory-copy/Documents" --output "./latest-documents-original-names" --restore-names

python3 "filehistory-latest-v1.py" --source "./FileHistory-copy/Documents" --output "./latest-documents-original-names" --restore-names --apply

依赖副本前先检查结果

阅读 summary.json,并用文本编辑器或电子表格查看器检查 manifest.csv。复制完成时,status 为 complete,且不存在 _INCOMPLETE.txt 标记。在清单中,用 source_relative_path 和 output_relative_path 追溯每个已复制文件,用 version_utc 查看选中版本的日期,用 sha256 查看记录的内容哈希。将 copied、older_version 和 unmatched 条目与汇总数量及报告的错误逐一核对。

工具通过 SHA-256 哈希检查已复制的文件内容。哈希一致可以作为复制字节与选中的源文件相符的依据,但不能证明该源文件原本就是完整、正常的,也不能证明备份包含了你期望的所有文档。

用平时使用的应用打开几个输出文档、图片或其他文件。检查范围应包括一个重要文件、一个有多个版本的文件,以及来自不同目录的文件。选一组已知文件,将输出版本的时间戳与源目录中现有版本比较。发现缺失或意外结果时,先回看预览和源文件,再决定能否把结果视为完整。

如果目的是释放磁盘空间,请记住,这个过程没有清理原备份。先验证仅含最新版本的副本,再另行决定是否保留原备份及旧版本。以后仍可能用得上这些旧版本,不要仅因新文件夹已经生成就删除它们。

命令未能完成时怎么办

如果 Python 找不到脚本,请检查终端当前所在文件夹,或提供脚本的完整路径。如果找不到源目录,请使用可读取备份实际挂载的位置。Windows 盘符不会自动变成 Linux 中可用的路径。

如果输出目录已经存在,请选择另一个尚未使用的目录。不要让下一次运行指向已有结果并期待更新或合并。执行复制时要保留预览使用的选项,包括此前选用的 --restore-names。如果恢复原文件名会使文件与目录发生路径冲突,请检查该目录结构,或使用默认的带时间戳输出名称。

预览或复制前检查失败时,会返回错误,不会创建输出目录。复制过程中失败,可能留下部分输出、_INCOMPLETE.txt,以及状态为 failed 或 in_progress 的汇总报告。如果报告本身也写入失败,summary.json 或 manifest.csv 可能缺失。只要终端报错、存在未完成标记,或缺少完成证据,就应把这次操作视为未成功。处理报告中的原因后,重新预览,再复制到另一个新输出目录。

排查期间请单独保留未完成的目录,工具不会自动删除它。不要将其中的文件与后一次运行结果混在一起,再把混合后的文件称为已验证结果。应使用同一次成功运行生成的清单和汇总报告,并打开检查对应文件,再决定保留什么。

仅含最新版本的集合有哪些局限

每组文件提供的是其中最新可用的保存版本,而各组版本可能来自不同日期。因此,这个集合不是电脑在某个特定时刻的快照。某个文件即使已从原电脑删除,备份中仍可能留有保存副本,并出现在这次结果中。

缺失的旧版本、不符合受支持格式的文件名、仅存于目录数据库中的信息,以及无法直接识别的存储路径,都不属于这一选择过程的处理范围。工具不会推断删除历史、重建这些路径,也不会认定无法识别的文件可以丢弃。

如果能够使用 Windows,并需要文件历史记录按日期逐次恢复的功能,可以参考微软记录的原生恢复方法。另一种现有方案 WindowsFileHistoryCleaner 已提供最新版本选择和预览模式。Mono 支持广泛的 .NET 功能,但本指南并未验证该特定项目在 Linux 上的配置方法。这里的流程只针对前文所述、可读取且文件名带时间戳的文件。

原创示意图展示 Work/report.txt、Work/report.pdf 和 Home/report.txt 分属三个版本组,各组选出自己的最新副本,图中使用了可选的 --restore-names 设置。
原创说明示意图:按相对目录和包含扩展名的完整原文件名分组。图中副本使用可选的 --restore-names;默认输出会保留选中版本带 UTC 时间戳的名称。 Watch at Ease