CompactOS 不是全盘 compact:一次 WOF 压缩导致 Windows 重启后无法启动的复盘

为了省系统盘空间,我用 compact.exe /EXE:XPRESS16K 对整块 C 盘做了递归压缩——包括 C:\Windows。压缩完 Windows 当时还能正常跑,重启后直接进了启动修复,而且修不好。最后靠离线解压 Windows 目录才救回来。这篇文章讲清楚这件事为什么会发生、怎么修、以及以后怎么安全地用 WOF 压缩。

📚 系列文章:本文是"装了一堆专业软件的电脑全面优化"系列的一部分。同系列还有 WOF 压缩科普与实操指南(WOF 是什么、怎么用、哪些目录最值得压)和 性能优化篇(CPU 降频、系统卡顿、开机慢的完整排障)。


起因:系统盘它又红了

故事要从一块装满了专业软件的三星 990 Pro 说起。

这台机器的配置不算寒酸——i7-13700H 处理器,NVMe 固态硬盘,放在生产力场景里完全够用。问题是它的主人是个"什么软件都要装"的工科人:NI、Autodesk、Siemens NX、SOLIDWORKS、Unity、Adobe 全家桶、Anaconda、STM32Cube、各类 SDK 和包缓存……

这些软件有一个共同特点:单个文件看起来很小,但目录树极深,文件数量极多。大量 XML、JSON、Python 包、Node 包、模板、语言包、示例文件、缓存文件、帮助文档、插件资源层层叠叠,最终把系统盘吃得非常夸张。

于是就有了一个很自然的想法——Windows 自带了一个叫 compact.exe 的命令行工具,支持 /EXE 参数用好几种压缩算法,据说对程序文件和只读资源效果很好。那何不试试?

先说结论:在 i7-13700H + Samsung 990 Pro 这种配置上,WOF 压缩系统文件的收益主要是省空间(几个 GB),而不是性能优化。事实上,对高性能 NVMe SSD 来说,压缩带来的额外 CPU 解码开销反而可能略微拖慢读取。所以这纯粹是一个"用 CPU 换硬盘"的交易。

当时的策略大概是这样的:下载、归档、冷备份目录偏向压缩率更高的 LZX;本地大部分程序和资源目录偏向 XPRESS16K,在压缩率和读取性能之间取个平衡;尽量都用 /EXE,这样被修改过的文件后续会自然退回非压缩状态。

这个策略在数据目录和软件资源目录上确实很有效,C 盘甚至回收了数百 GiB 的空间。问题出在边界:它不应该递归压到 C:\Windows


先搞清楚:Windows 的"新式压缩"到底是什么

很多人一听到"Windows 压缩",脑子里浮现的是文件属性里那个"压缩内容以便节省磁盘空间"的勾选项——那是传统 NTFS 压缩,历史悠久,效果一般。

compact.exe /EXE 和微软的 CompactOS 用的是另一套机制,它和 WOF(Windows Overlay Filter)紧密关联,专门为"频繁读取但很少修改"的文件设计。简单做个区分:

类型 典型入口 特点
传统 NTFS 压缩 文件属性勾选、compact /c 更老、更通用,目录可以被标记为"新文件自动压缩"
WOF /EXE 压缩 compact /EXE:XPRESS16Kcompact /EXE:LZX、CompactOS 面向程序文件、OS 二进制、资源文件,压缩率通常更好

/EXE 支持的四种算法,大致可以这样理解:

算法 倾向
XPRESS4K 最快,压缩率最低
XPRESS8K 折中
XPRESS16K 压缩率和读取开销比较均衡
LZX 压缩率最高,但压缩和读取开销也更高

这类压缩特别适合程序安装目录、SDK、帮助文档、模板、示例工程、Python/Node/Java 包缓存、大量 XML/JSON/HTML 文本资源、以及各种不常修改的冷数据。它不适合已经压缩过的文件(视频、照片、zip/7z、dmg、iso、exe 安装包),这些再压基本是白费力气。

这次事故不是因为新式压缩"不好用"。恰恰相反,它非常好用,空间收益很夸张。真正的问题是:它被用到了启动链不该被手动递归处理的地方。


事故现场:一切看起来都很好,直到重启

压缩执行完毕以后,当前 Windows 会话仍然可用。桌面正常,软件能打开,文件访问没有异常。

这点非常迷惑。如果一个操作会导致系统无法启动,直觉上似乎应该马上出问题——蓝屏、资源管理器崩溃、文件打不开。但实际情况不是这样。当时的系统看起来就像做了一次完全无害的磁盘整理。

真正的问题发生在重启时:

  • UEFI/BIOS 层面没有提示找不到硬盘
  • Windows Boot Manager 能进入启动链
  • 随后进入 Windows 自动修复
  • 自动修复失败
  • 强制关机再开机,仍然重复进入恢复环境

这说明问题大概率不在硬盘识别,也不在 EFI 启动项,而是在 Windows 本体加载阶段。

这里有一个非常重要的判断:

这不是"系统盘坏了",也不一定是"必须重装系统"。它更像是 Windows 目录里一批启动关键文件处在了启动环境无法接受的压缩状态。

这个区别很重要,因为很多人看到自动修复失败会立刻以为系统废了,然后开始重装。实际上只要文件本体还在、分区也能挂载,通常可以通过另一套 Windows 或 WinPE 把 Windows 目录解压回来。


离线排查:关键证据浮出水面

把系统盘挂到另一台机器上做离线检查,发现了非常有意思的现象:

未被压缩的文件:

  • Windows\System32\winload.efi
  • Windows\System32\winresume.efi

被 WOF 压缩的文件:

  • Windows\System32\ntoskrnl.exe(Windows 内核)
  • Windows\System32\hal.dll(硬件抽象层)
  • Windows\System32\ci.dll(代码完整性)
  • Windows\System32\drivers 下大量 .sys 驱动,共 551 个全部被压缩

在文件属性层面,这些文件都带有 WofCompressedData 备用数据流(Alternate Data Stream),这是 WOF 压缩的标志性特征。如果你想自己诊断一个文件是否被 WOF 压缩,可以用 compact /a 查看,或者在支持显示 NTFS 备用流的工具里检查这个属性。

其中包括一批非常早期的启动关键驱动:

ntfs.sys        文件系统驱动
disk.sys        磁盘驱动
stornvme.sys    NVMe 存储驱动
storport.sys    存储端口驱动
volmgr.sys      卷管理器
volmgrx.sys     卷管理器扩展
wof.sys         Windows Overlay Filter 本身
fltMgr.sys      过滤管理器
acpi.sys        ACPI 驱动
pci.sys         PCI 总线驱动

还有一个很有意思的验证方式:在 macOS 上只读挂载这个 NTFS 分区,直接读取那些被 WOF 压缩的文件,文件头显示为全零,而不是正常 Windows PE 文件应有的 MZ

这说明文件的真实内容并不在普通 NTFS 文件流里可以直接读取——它被放进了 WOF 压缩数据层,需要 Windows 自己的 WOF 机制来解包。

⚠️ 警告:如果你也是在 macOS 上挂载发现的问题盘,千万不要用 Paragon NTFS、Tuxera NTFS 等 macOS 侧的 NTFS 写入工具尝试修复。WOF 压缩数据的结构需要 Windows 自己的 WOF 机制处理,macOS 侧的写入很可能进一步破坏文件,让原本可救的数据真的无法恢复。


为什么压完当时没事?

这个问题的答案其实很优雅:因为当时 Windows 已经启动完成了。

运行中的 Windows 已经把内核、HAL、文件系统驱动、存储驱动、过滤驱动等关键组件全部加载进了内存。WOF 过滤机制(也就是 wof.sys)也已经在当前运行环境中工作。在这个状态下,即使后续需要读取某些 WOF 压缩文件,Windows 完全可以通过自己的文件系统栈把内容解出来。

所以"压完以后当前会话没崩"并不能证明系统目录被这样压缩是安全的。

有一个很形象的比喻:

当前系统已经站在桥的另一边,所以它能读桥这边的东西。但重启后,它需要先走过那座桥——而桥已经被自己拆了。此之谓:过河拆桥。


为什么重启后才爆炸

重启后加载顺序变了。

正常的 Windows 启动链条大概是这样的:UEFI 固件 → Windows Boot Manager → winload.efi → 加载内核(ntoskrnl.exe)、HAL(hal.dll)、代码完整性(ci.dll)→ 加载文件系统驱动(ntfs.sys)、磁盘驱动(disk.sysstornvme.sys)、卷管理驱动(volmgr.sys)→ 加载其余驱动和系统服务 → 登录界面。

这次事故里,winload.efi 本身没有被压缩(前面离线检查已确认),所以启动链的前半段能正常走通。但 winload.efi 接下来要加载的一批核心文件——内核、HAL、代码完整性、文件系统驱动、磁盘驱动——全部被手动 /EXE 递归压缩过了。

这就形成了一个启动依赖死锁

  1. 系统需要加载 ntoskrnl.exehal.dllci.dll
  2. 系统需要加载 ntfs.sysdisk.sysstornvme.sysvolmgr.sys 等驱动
  3. 这些文件都处在 WOF 压缩状态
  4. 但早期启动环境不等价于完整运行中的 Windows 文件系统栈——此时 WOF 过滤器还没加载起来
  5. 于是加载 Windows 本体失败,系统掉入自动修复循环

这也是为什么回退 Windows 目录的压缩以后,系统就能恢复启动。


CompactOS 和手动全盘 /EXE 压缩不是一回事

这次事故最容易误判的地方在于:Windows 官方确实支持 CompactOS,而且微软文档明确说 Windows 10 和 Windows 11 可以从压缩的操作系统文件运行。

所以结论不能简单写成"WOF 压缩系统文件一定不能启动"——这个说法太粗糙,也不准确。

更准确的说法是:

官方 CompactOS 是受控的系统压缩模式。它由 Windows 自己决定哪些文件该压、怎么压、压到什么粒度,同时启动链知道并支持这种状态。而手动对 C:\Windows 或全盘递归执行 /EXE:XPRESS16K/EXE:LZX,绕过了这个受控边界,把启动早期链路不该碰的文件也卷了进去。

二者表面上都用了压缩,但风险边界完全不同。

这也解释了为什么修复后 compact /CompactOS:query 可能仍然显示系统处于 Compact state,而且用 compact /a 查看某些系统文件可能仍然看到"压缩"——这并不矛盾。这说明系统可能正处于官方 CompactOS 的受控状态,而不是事故时那种手动递归全盘 /EXE 的失控状态。

问题从来不是"压缩"两个字本身,而是:谁压的、用什么入口压的、压了哪些边界、启动链是否知道并支持这种状态。


修复方法:先别急着重装

如果系统已经因为手动 WOF 压缩 Windows 目录而无法启动,这里有一个非常朴素但有效的修复思路:

不要急着重装。先找一个能正常运行 compact.exe 的 Windows 环境,把离线系统盘里的 Windows 目录解压回来。

具体步骤

第一步:准备一个可用的 Windows 环境。 可以是 WinPE U 盘启动,也可以把系统盘挂到另一台 Windows 电脑上。

第二步:确认离线系统盘的盘符。 不要凭感觉猜。逐个看:

dir G:\Windows
dir H:\Windows
dir I:\Windows

哪个盘符下能看到熟悉的 System32WinSxSexplorer.exe,哪个才是目标 Windows 分区。

第三步:解除 WOF 压缩和传统压缩。 假设离线系统盘符是 G:

compact /u /a /i /f /exe /s:G:\Windows
compact /u /a /i /f /s:G:\Windows

第一行解除 /EXE WOF 压缩(XPRESS/LZX 那套)。第二行解除传统 NTFS 压缩并清理目录压缩标记。

第四步:验证关键文件。 重点检查:

compact /a G:\Windows\System32\ntoskrnl.exe G:\Windows\System32\hal.dll G:\Windows\System32\ci.dll
compact /a G:\Windows\System32\drivers\ntfs.sys G:\Windows\System32\drivers\disk.sys G:\Windows\System32\drivers\wof.sys

确认这些文件不再显示压缩状态。

第五步:把盘装回去,尝试正常启动。

几个常见坑

不要在同学的电脑上直接执行:

compact /CompactOS:never

因为这会作用于当前运行的系统,而不是离线挂载的那块盘。你本来想救别人的电脑,结果把同学正在跑的 Windows 给解压了。

/WinDir 参数只对查询有效:

compact /CompactOS:query /WinDir:G:\Windows

这样可以查询离线系统的 CompactOS 状态。虽然从语法层面看 alwaysnever 似乎也接受 /WinDir,但实测中行为不稳定,不建议依赖这个组合。修复离线系统时,老老实实用 compact /u /exe 逐目录解压更可靠。

如果系统盘开了 BitLocker: 需要提前准备恢复密钥。否则离线环境可能看不到真实文件内容,或者只能看到加密分区。

从这次经验看,只要能把 Windows 目录解压回来,通常不需要重装系统。重装应该是最后手段,不是第一反应。


以后怎么安全地用 WOF 压缩

这次事故之后,压缩策略应该从"全盘递归"改成"白名单目录 + 明确排除系统启动链"。

永远不要手动递归压缩

C:\Windows
C:\Boot
C:\Recovery
C:\System Volume Information
EFI System Partition
Windows RE / WinRE 相关分区

尤其不要对 C:\Windows\System32C:\Windows\System32\driversC:\Windows\WinSxS 做手动 /EXE 递归。

如果确实想压缩系统文件,只用官方入口:

compact /CompactOS:always

想回到最稳妥状态:

compact /CompactOS:never

可以放心压缩的区域

这些才是 WOF 压缩真正的主场:

专业软件资源目录(Autodesk、Siemens、Unity 等)
SDK 和开发工具链
帮助文档、模板文件、示例工程
Anaconda / Python 包、Node 包缓存
Gradle / Maven 缓存
Unity / Unreal / CAD 软件资源
下载归档、冷备份目录

按目录白名单执行比从 C:\ 根目录直接递归安全得多。例如:

C:\Program Files\Autodesk
C:\Program Files\Siemens
C:\Program Files\Unity
C:\ProgramData\anaconda3
C:\Users\<User>\.gradle
C:\Users\<User>\.nuget
C:\Users\<User>\AppData\Local\pip

策略虽然麻烦一点,但边界可控。

收益低但可以试的区域

这些文件通常已经被压缩过,再压收益很低,但一般不会出问题:视频、照片、zip/7z/rar、dmg、iso、exe/msi 安装包。可以压,但要有心理预期——更多是"顺手抠一点",不是主要收益来源。

如果写自动化脚本

建议默认排除系统目录:

$excludePrefixes = @(
    'C:\Windows',
    'C:\Boot',
    'C:\Recovery',
    'C:\System Volume Information'
)

并且按白名单目录执行,而不是从盘符根目录递归。


应急速查清单

如果你也因为手动压缩系统目录导致 Windows 重启后进恢复环境,按这个顺序判断:

  1. 先不要重装。
  2. 确认 BIOS/UEFI 还能识别硬盘。
  3. 如果能进入 Windows 恢复环境,说明启动链至少走到了一部分。
  4. 用 WinPE 或另一台 Windows 挂载系统盘。
  5. 找到离线系统的 Windows 目录(用 dir 确认,不要猜盘符)。
  6. 执行 compact /u /a /i /f /exe /s:<盘符>:\Windows
  7. 再执行 compact /u /a /i /f /s:<盘符>:\Windows
  8. 检查 ntoskrnl.exehal.dllci.dll 和关键 .sys 驱动是否已解压。
  9. 装回去,尝试启动。

最重要的是:只要文件还在、分区没坏,这类事故通常有很大概率能救回来。


经验教训

这次事故有几个很值得记下来的教训:

  1. compact.exe /EXE 很强,但不能无脑全盘递归。C:\Windows 不是普通数据目录。
  2. CompactOS 是官方受控系统压缩,不等于手动全盘 /EXE。两者风险边界完全不同。
  3. 系统运行时没崩,不代表下一次启动不会崩。"延迟爆炸"是最容易让人放松警惕的事故模式。
  4. 离线环境能不能直接读文件头,是判断 WOF 依赖风险的一个很有用的线索。
  5. 真正适合大规模压缩的是专业软件资源、包缓存、SDK、文档、模板、冷数据。
  6. 对系统盘做这种操作前,必须有离线恢复方案和操作日志。
  7. 进恢复环境不等于必须重装。先尝试离线解压 Windows 目录。
  8. 系统目录如果要压缩,优先使用 compact /CompactOS:always

结论

这次事故不是"WOF 压缩不能用"。恰恰相反,它证明 WOF 压缩非常有效——在专业软件、开发环境、包缓存、归档目录上,它能回收非常可观的空间。

但它也证明另一件事:

压缩策略针对系统文件夹务必三思而后行。数据目录可以大胆,系统目录必须保守。

如果只记住一句话,希望是这句:

新式压缩很好用,CompactOS 也确实能稳定压缩 Windows。危险的是把普通文件清理思路套到 C:\Windows 上,手动递归压缩整个启动链。

这是一次很典型的延迟爆炸事故:操作当场看起来成功,真正的问题藏到了下一次启动。

不得不说,修好了之后,WOF比NTFS自带的传统压缩真的香太多了哈哈哈~


参考资料

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐