侧边栏壁纸
博主头像
一笑痕

仙人之下我无敌,
仙人之上一换一。

  • 累计撰写 67 篇文章
  • 累计收到 7 条评论

cp -c 一秒拷完 6000 个文件,磁盘却几乎没多占

2026-9-19 / 0 评论 / 6 阅读

cp -c 一秒拷完 6000 个文件,磁盘却几乎没多占

把 node_modules 拷一份做备份,cp -R 跑了半天,磁盘占用还翻倍。macOS 的 APFS 文件系统其实藏了一条近路:clonefile。本篇按教程体的三步走,每步都能单独跑,数据全部来自本机实测(脚本 tools/verify-cp-clonefile.sh,/tmp 临时目录,跑完即删)。

第一步:知道 -c 是什么

man cp 里对 -c 的说明是:拷贝时使用 clonefile(2)。clonefile 是 APFS 提供的写时复制克隆:文件系统不给新文件分配数据块,只把目录项指向同一批物理块,两个路径从此独立,任何一边写入才真正占新空间。

一个容易误解的点先说清:克隆出来的文件不是硬链接。硬链接是两个名字共享同一个 inode,动一个另一个跟着变;克隆是两个独立的 inode,内容恰好共享物理块。改克隆出来的文件,原文件不受影响。删掉其中一个路径,另一个照常能读,数据也还在。

第二步:跑一次对比

造一个 6000 个文件、约 47MB 的目录树(模拟小型 node_modules),分别用两种方式拷:

源目录大小: 47M

=== 三种拷贝,各跑 1 次 ===
cp -R      (逐字节写盘): 0.69 秒
cp -c -R   (clonefile) : 0.55 秒

0.55 秒对 0.69 秒,快约两成。6000 个小文件的场景瓶颈主要在目录项操作,clonefile 的优势没有想象中大。文件更大、更少的场景差距会拉开,这一条在本机没测,留给读者按需验证。

顺带一提,clonefile 在 Linux 上也有对应物:btrfs 和 XFS 支持 reflink,cp --reflink=auto 走的就是这条路。语义和 APFS 的克隆一致,写时复制、物理块共享。所以这篇的结论不止 macOS 适用,两边的文件系统早就把同一件事各做了一遍。

第三步:验证磁盘真的没多占

快不算本事,关键是省空间。看克隆文件实际分配的块数:

=== clone 出的文件,磁盘上真实分配的块数(st_blocks,512B/块)===
cp -R  : 文件 7000 字节,占 16 块 = 8192 字节
cp -c -R: 文件 7000 字节,占 16 块 = 8192 字节

这个结果反而说明 clonefile 省的是另一头:源文件和克隆文件加起来,物理块只存一份。du 看单个文件时把共享块各算了一遍,所以两行数字一样,但整卷的剩余空间只少了一次 7000 字节的量。想看整卷真实变化,得对比拷贝前后的卷剩余块数,单看 st_blocks 会得出「没省」的错结论,第一次跑的时候就在这里误判过。

检查点:什么时候能用

三个判断依据,按序检查:目标路径和源路径在同一个 APFS 卷上(跨卷 clonefile 直接失败,cp 会回退成普通拷贝但不报错,等于白加 -c);目标卷有足够 inode(克隆还是要建目录项和 inode 的);对拷贝产物有「立即独立占盘」的需求时别用(写时复制意味着占盘发生在写入那一刻)。

我的取舍:临时备份、复现环境、拷 node_modules 这类一次性目录,一律加 -c。要长期归档的还是 rsync 或 tar,克隆块在源文件被覆盖写入后会逐步解共享,归档要的是确定性,不是省这一下。

    🤞 分享