"Meta" Data / 元数据的历史
Redshift_Shine · · 科技·工程
AI 创作声明:本文由 Claude Sonnet 4.6 模型辅助创作。保证本人的贡献大于该模型的贡献。
在关于 2026 年山东省选作弊问题的举报信一文中,压缩文件夹中与众不同的修改时间成为了证据之一。在对此事感到愤慨的同时,我开始好奇:操作系统是如何处理文件修改时间的?这显然是文件元数据的功劳,那么元数据是如何演变成现在的样子的?
于是,我向 Claude Sonnet 4.6 提出了这个问题。祂向我讲述了这样一个故事。当然,下面的内容并不是祂故事的原文,要不然我也不会说“我的贡献大于 AI 的贡献”了。
手写元数据
计算机刚出现时还不具备管理文件的功能。准确来说,最初的计算机只是用来进行数学运算的,并没有成为一个真正独立的系统。因为没有文件,自然没有存储在硬盘中的源代码。所以,那时的源代码是写在打孔卡上的。
打孔卡就是一张卡,因此为了方便管理,会用笔在打孔卡上写上这张打孔卡的作用以及其打孔日期。这就是元数据的初始形态。顺带一提,早期版本的 VS Code 会在第 80 列处显示一条分割线,其原因就是从 IBM 打孔卡规定一行只有 80 个孔开始,一行代码不超过 80 个字符这一共识就广泛存在了。
Multics
1965 年,Multics 操作系统诞生,其为世界上第一个提供层次化文件系统的操作系统。该系统的文件系统支持任意长度的文件名,并且已经拥有了符号链接的功能(类似于如今 Linux 系统下的 ln 指令)。
Multics 的文件元数据中会存储该文件的所有者、权限、访问控制信息以及使用频率,因此会将不常用的文件下放至低级存储设备。然而,即便拥有如此多的在当时看来具有革命性的设计理念,这个文件系统里仍然没有时间戳的概念。
Unix inode
正如上面所提到的,Multics 对于那个时代来说太超前了,如同生不逢时的 Windows Vista。于是,以 Multics 文件系统为参考的 Unix 文件系统诞生了。
Unix 文件系统引入了 inode(index node),这个数据结构就用来存储文件元数据。inode 维护了三个时间戳,atime(最后读取或执行操作的时间)、mtime(内容变更的修改时间)和 ctime(权限修改等元数据更新的变更时间),这三个时间戳组成了描述一个文件生命周期的基本结构。
值得注意的是,inode 并不包含文件本身,而是指向文件。换言之,若将 Unix 文件系统的文件夹结构画成一棵树,那么这棵树的每个叶子并不是文件本身,而是指向文件的 inode。
当某个程序获取了一个文件的信息并使用时,其获取的实际信息可能为那个 inode 而非文件本身。在这种情况下,就算在程序运行时对那个文件进行了更改,在那个程序眼里,文件仍然没有发生变动。
FAT
FAT(File Allocation Table),最初作为 DOS 和 Windows 9x 操作系统的默认文件系统而开发。由于当时的硬件条件极差,FAT 的文件夹使用了一种简陋到极点的方法进行实现:将元数据直接嵌入到目录或文件中,目录中的每个项指向对应子文件或子文件夹的第一个簇。
同时,由于 FAT 作为文件所占据的空间在格式化时就被确定且无法再改变,FAT 根据其可描述文件大小分为了若干个子类,如 FAT12,FAT16,FAT32。FAT32 作为目前的最新版本,最高支持 16TB 的容量和 4GB 的单个文件。
FAT 只为文件和文件夹设计了四种属性:Archive(归档)、Hidden(隐藏)、System(系统)和 Read-only(只读)。同时,FAT 中修改时间精度只有 2 秒,访问时间精度只有 1 天,时间戳以本地信息存储,并且不存储时区。显然,这种简陋的元数据无法适应跨时区工作的需要。
HPFS / NTFS
IBM OS/2 创造了名为 HPFS(High Performance File System)的文件系统。由于在此系统中,目录项指向的不是文件的第一个簇而是一个 FNODE,其元数据的维护能力大大增强。尽管这种文件系统仅能对大小在 400MB 以下(你没听错)的分区提供良好性能,这也仍然是在元数据内提供详细信息的第一次尝试。
1993 年,NTFS 随 Windows NT 发布,这也是目前在 Windows 系统内使用最广泛的文件系统。在 NTFS 卷中,一个文件的名字、所有者、时间戳、内容等信息都以“文件属性”的形式呈现。没错,内容也是一个属性,被称为 $DATA。
NTFS 的时间戳在设计之初就使用 64 位类型进行存储,包含创建时间、最后修改时间、最后访问时间和 MFT 变更时间,起始时间为 1601-01-01 00:00:00 UTC,精度为 100ns。而这,距离 Unix 时间戳跨入 64 位时代还有十年时间。NTFS 首次引入了 UTC 时间存储,将本地时区转换的工作交给应用层,成功避免了 FAT 中出现的时区混乱问题。
不止于基础数据
1995 年,BeOS 问世。BeOS 在 BeBox 硬件上运行,其使用的文件系统 BeFS 支持了不止于上述属性的扩展文件属性,并且因其设计时所预想的用途(多媒体系统)而被广泛用于基础程序和第三方程序。
文件扩展属性,顾名思义,就是不同于文件基本属性的属性。这些属性可以由软件所定义,也可以由用户自行定义。这些信息可以包含文档作者、字符编码、校验和和数字证书等等。同样的,也可以存储访问控制信息。
Linux 同样支持扩展属性,不过这个功能(xattr)在 2002 年左右才被加入主线内核,其主要有四个命名空间:user、trusted、security、system。system 命名空间主要由内核使用,用于控制访问控制列表;security 命名空间主要被 SELinux(Security-Enhanced Linux,Linux 安全套件)使用。
创建时间去哪了?
如果你翻回文章开头再次仔细阅读 Unix 文件系统的时间戳体系,就会发现一个问题。没有创建时间。
Linux 用于查看文件信息的新型接口 statx 在 2010 年首次提出,并在 2017 年被合并入 Linux。然而,在此之后,并没有对于文件属性命名的明确规则,因此 Linux 上的不同文件系统完全按照自己的想法命名创建时间:ext4 和 XFS 使用 crtime,而 Btrfs 和 JFS 使用 otime。glibc 在 2018 年才加入了对 statx 的完全支持,2019 年 3 月 GNU coreutils 的 stat 命令才正式支持文件创建时间的读取。
元数据的未来
跨入 SSD 和极高频率读写的时代后,保证数据在读写过程不出差错成为了一件十分重要的事情。这也是 ZFS 采用写时复制(CoW)和元数据校验和来保证文件无论元数据正确与否都可以正常访问的原因。
2008 年发布的 ext4 将时间精度提升至纳秒,同时将时间戳有效范围大幅增加,避免了 32 位时间戳面临的 2038 问题。
苹果在 2017 年发布了从零设计的 APFS。得益于其较晚的设计时间和苹果构建的独立生态,APFS 可以对苹果自家硬件进行专门优化。在此之前,苹果使用 HFS+,缺少了很多现代硬件需要的功能,如纳秒时间戳、校验和、快照和稀疏文件支持。APFS 完全支持上述特性,并且在时间戳组合中包含了 birth time,组成了完整的四时间戳系统。
由此,我们跨越了七十多年的时间,见证元数据系统与硬件条件的提升一同进步,也明白了为何现在的文件都有如此丰富的附带信息。
更重要的是,我们也明白了,为何只需要简短到极点的六行代码,正义就可能迟到远远更久的时间:
(Get-Item "recollector.cpp").LastWriteTime = "2026-03-07 14:21:00"
(Get-Item "string.cpp").LastWriteTime = "2026-03-07 14:21:00"
(Get-Item "night.cpp").LastWriteTime = "2026-03-07 14:21:00"
(Get-Item "perm.cpp").LastWriteTime = "2026-03-08 14:39:00"
(Get-Item "starmap.cpp").LastWriteTime = "2026-03-08 14:39:00"
(Get-Item "industry.cpp").LastWriteTime = "2026-03-08 14:39:00"
因为,对于个人用户来说,操作系统根本就不关心你的文件的修改时间。
关心它的,是我们。
是真理的追寻者。