C盘红了,这大概是Windows用户最不想看到的几个字之一。而如果电脑上装了WSL,C盘变红的原因里十有八九有它一份。WSL2默认把整个Linux环境塞在一个叫ext4.vhdx的虚拟磁盘文件里,位置在%LOCALAPPDATA%\Packages\...\LocalState下面,这个文件少则几个GB,多则十几二十个GB。日常开发装软件、跑Docker、放数据,这个文件还会继续膨胀,很快C盘就被一点点吃完了。
与其想办法清理碎片,不如干脆把整个WSL发行版搬到D盘或者E盘去。这件事听上去有点吓人,其实官方早就留了标准通道:用wsl --export和wsl --import这对命令,把整个发行版打包导出,然后换个盘符重新导入,整个过程顺利的话半小时内就能搞定。这篇文章我就把完整操作流程、每一步背后的原因、以及我实测踩过的坑全部讲清楚。不管你是第一次迁移的新手,还是已经翻了一堆教程还卡在某个报错里的老手,这篇都值得从头到尾扫一遍。
1. 迁移前,先想清楚这三件事
1.1 为什么WSL不能直接复制文件夹到新盘
不少人第一反应是:把WSL的目录整个剪切到D盘,再改个路径不就行了?这个思路在普通软件上行得通,但在WSL这里会撞墙。
WSL2本质是一个轻量虚拟机,Linux发行版的文件系统不是以普通文件夹的形式暴露给Windows的,而是被打包在一个虚拟磁盘文件ext4.vhdx里。Windows侧只知道这个发行版在WSL的注册表里有一项记录,里面保存了发行版名称、安装目录等元信息。你单独把ext4.vhdx或者整个WSL目录挪走,Windows并没有更新注册信息,下次启动WSL时照样去老位置找文件,结果就是找不到、启动失败。
WSL1的情况稍有不同,它的发行版以普通文件夹形式放在%LOCALAPPDATA%\Lxss下,但同样存在“注册信息没有同步更新”的问题。所以无论哪种情况,官方推荐的迁移路径都是:先导出、再注销、最后导入。这个过程相当于把你的整套Linux环境打包成一个tar包,然后在新地址重新“解压入住”,注册信息由WSL自己重建,逻辑干净,也不容易留尾巴。
1.2 动手前先盘点你的WSL环境
迁移之前,先搞清楚自己到底装了什么,这一步非常关键,能避免迁移到一半才发现漏了数据。
打开PowerShell或者Windows Terminal,执行:
wsl --list --verbose正常会输出类似这样的信息:
NAME STATE VERSION * Ubuntu-22.04 Running 2这里能看到三样东西:发行版名称、当前状态、以及WSL版本号。发行版名称后面会反复用到,建议先记下来。以我自己的机器为例,迁移前装的是Ubuntu-22.04,VERSION列是2,说明是WSL2。
然后进到WSL里面,大概看一眼Home目录下有哪些用户、装了哪些关键服务。我的Ubuntu里当时有Python虚拟环境、Node项目、Docker数据卷,还装了一堆APT包,导出的tar包有7.2GB。迁移后这些组件基本都能原样跑起来,但提前心里有数,后面验证的时候才知道该测什么。
如果机器上装了多个发行版,建议一个一个来,不要同时处理多个。每个发行版都有一套独立的虚拟磁盘,分开做更稳妥,也能避免操作失误时一起遭殃。
1.3 目标盘选择与目录规划
目标盘这一步,我见过不少人在这里翻车。核心要求有这么几条:
- 目标盘必须是NTFS格式。WSL不支持FAT32、exFAT这类分区格式,老老实实选NTFS就行。
- 路径不要有中文,不要有空格。WSL对这些路径的解析偶尔会出现奇怪的问题,反正都是自己建的目录,用英文字母最省心。
- 目录结构提前规划好。推荐分两个目录,一个放正式的发行版数据,一个放导出的tar备份。例如:
D:\WSL\Ubuntu-22.04 D:\WSL\backup\ubuntu2204.tar这样tar文件和发行版本体都在D盘,整个迁移过程基本不消耗C盘空间,对C盘已经爆红的用户特别友好。
空间预估上,建议目标盘剩余空间至少是当前虚拟磁盘文件大小的1.5倍。原因很简单:tar包导入后会生成新的ext4.vhdx,如果tar本身就很大,新虚拟磁盘是动态扩展的,会占掉不少空间。假如你现在C盘上WSL占了20GB,那D盘至少留30GB以上才比较从容。另外说明一点,导出后的tar包大小通常比vhdx文件小很多,因为tar只包含实际使用的文件内容,而vhdx里可能有未释放的“空洞”。所以就算tar只有7GB,新vhdx实际大小也可能在9GB以上,别拿tar大小去判断磁盘占用。
2. 正式开工前的三个准备动作
2.1 把tar文件当成备份,提前多留一手
迁移的整个过程,实际上有一个天然的保底方案:导出的tar包本身就是整个WSL环境的完整备份。只要这个tar包还在,你就永远有后悔药吃。
不过我不建议只依赖这一层保险。动手之前,先确认一下WSL里有没有什么必须保留、不能丢失的数据。比如数据库的数据目录、某个关键项目里还没提交的代码、某些带许可证的软件配置。这些数据如果丢了,单纯靠tar包可能能找回来,但恢复的成本会高不少。
更稳妥的做法是:顺手把关键目录单独复制一份到外部盘或者是Windows的另一个分区。我习惯在迁移前对数据库做一次dump导出,比如PostgreSQL的pg_dump或者MySQL的mysqldump,Linux环境下做这个操作非常简单。万一迁移后系统起了什么幺蛾子,数据还在,不影响工作进度。
2.2 彻底关闭WSL,避免文件占用
这一步特别重要,很多人第一次迁移失败就栽在这里。
WSL2运行时,负责承载Linux环境的虚拟机进程会一直占用ext4.vhdx文件。如果你不关闭WSL就直接执行导出,轻则导出失败,重则导出的tar包损坏,等于白跑一趟。更麻烦的是,如果此时还有VSCode Remote-WSL窗口、终端里的WSL会话、或者是其他调用WSL的软件在后台运行,这些进程都会和虚拟磁盘建立连接,导致文件被锁定。
正确的做法是:
- 关闭所有WSL相关的窗口,包括终端、VSCode远程窗口,以及其他可能调用WSL的程序。
- 在PowerShell里执行:
wsl --shutdown这条命令会把所有WSL发行版和对应的虚拟机进程全部停止。执行完可以再跑一次wsl --list --verbose,如果所有发行版的STATE都变成了Stopped,说明已经彻底关闭。
还有个细节,wsl --shutdown执行后并不会马上释放所有内核句柄,如果你急着立刻做下一步,可以等个几秒让系统把资源回收干净。不用太夸张,深呼吸的时间就够。
2.3 确认WSL版本和命令可用
迁移依赖wsl --export和wsl --import这两个命令,理论上只要WSL不是上古版本,都能用。但为了保险,建议先确认一下版本。
wsl --version如果提示找不到这个命令,说明你的WSL版本比较老,或者还停留在Windows自带的早期版本。解决办法很简单,执行:
wsl --update有些网络环境下这一步下载可能会比较慢,耐心等一会就行。如果实在卡住,也可以直接去微软官网下载WSL离线安装包手动更新。先把版本搞定,后面整个迁移流程才会顺畅。
另外说明一下,这个流程普通权限基本就能跑通。如果导出或导入时碰到奇怪的权限报错,再右键“以管理员身份运行”PowerShell重试,一般都能解决。
3. 迁移三步走:导出、注销、导入
3.1 第一步:导出发行版tar包
先找到PowerShell或Windows Terminal,然后执行:
wsl --export Ubuntu-22.04 D:\WSL\backup\ubuntu2204.tar命令格式是wsl --export <发行版名称> <导出文件路径>。第一个参数填你从wsl --list --verbose里看到的发行版名称,第二个参数是tar包要保存到哪。这里有一个经验:导出路径一定要放在C盘之外。原因前面提过,就是避免tar包本身又往C盘塞几个GB,让本来就不宽裕的C盘雪上加霜。
执行后终端会“卡住”没有任何输出,这个现象是正常的。导出期间WSL正在把整个文件系统打包成tar,任务量大时会持续几分钟。我自己的7.2GB的tar包大概跑了三四分钟,期间可以去倒杯水,但别关终端。想确认它是不是真的在工作,可以另开一个窗口看D盘对应位置的文件大小是不是在持续增长。
关于进度提示,Windows原生的wsl --export不带进度条,这是常态。如果实在不放心,也可以直接看目标文件大小变化。导出结束后tar包的大小基本稳定在你预期范围内,就可以进行下一步了。
3.2 第二步:注销原发行版并释放C盘空间
tar导出来之后,接下来就是和C盘上的旧文件做个了断。执行:
wsl --unregister Ubuntu-22.04这个命令会把发行版从WSL的注册表里移除,并且清理掉它对应的虚拟磁盘文件,也就是最占空间的那个ext4.vhdx。这样C盘的空间才算真正释放出来。
这一步是整个流程里风险最高的一环,因为wsl --unregister是不可逆的删除操作。它会删除发行版里所有文件,不经过任何回收站。所以在执行前,务必再确认一遍:
- tar包已经导出成功,而且文件大小看起来合理(如果原本环境有五六个GB,导出的tar却只有几十MB,那大概率导错了发行版或者导出过程出了问题)。
- 关键数据有额外备份,不是只靠这一份tar。
确认无误后再敲回车。执行后WSL列表里这个发行版就消失了,C盘空间也会随之释放。如果空间没有立刻变多,通常是因为磁盘索引还没刷新,可以稍等一会,或者打开资源管理器刷新一下。正常情况下,%LOCALAPPDATA%\Packages\...\LocalState下的ext4.vhdx文件应该已经被删掉了,如果还在,说明有进程占用着虚拟磁盘文件,重启电脑后再看看就行。
注意:如果你只想备份、不打算真的迁移,到这里就该停手了。
wsl --unregister不是必须执行的步骤。我的个人习惯是,只要tar包已经存在,注销旧发行版就是一次“安全拆除”,但前提是心里对tar包有把握。
3.3 第三步:导入到新盘符并恢复默认用户
先创建好目标目录,然后执行导入:
mkdir D:\WSL\Ubuntu-22.04 wsl --import Ubuntu-22.04 D:\WSL\Ubuntu-22.04 D:\WSL\backup\ubuntu2204.tar --version 2注意这几个参数的位置:第一个参数是发行版名称,第二个是新的安装目录,第三个是刚才导出的tar包路径。--version 2的意思是强制导入为WSL2,如果你的WSL原本就是2,加不加都行,但显式写出来更安全,避免某些环境默认导入成其他版本的意外情况。
导入过程同样没有进度条,终端会静默运行一段时间。完成后执行wsl --list --verbose,能看到发行版回来了,而且正常显示为WSL2。
但这个时候还不能高兴太早,因为导入后有一个非常典型的坑:默认用户会变成root,而不是你原来是普通用户。原因在于tar包只备份了文件系统内容,导入时WSL要为发行版重新建立“默认用户”的映射。既然找不到原来的映射记录,就干脆回退到root。
解决办法分成两步走。先用root身份进入发行版,看看原来的用户名是什么:
wsl -d Ubuntu-22.04 -u root进去后执行:
ls /home正常情况下能看到你原来的用户名目录,比如zhangsan。记下这个名字。接着编辑WSL的配置文件:
sudo vi /etc/wsl.conf如果文件不存在就新建一个,写入以下内容:
[user] default=zhangsan保存退出后,回到Windows侧执行:
wsl --shutdown然后再启动WSL,就会以zhangsan的身份登录了。
另外,新版WSL其实提供了一条更简单的命令:
wsl --manage Ubuntu-22.04 --set-default-user zhangsan如果你的WSL版本支持这条命令,直接用更方便。不支持的话,就按改/etc/wsl.conf的方式处理,两种方法殊途同归。
3.4 迁移结束后的清理与确认
导入成功、默认用户恢复之后,先别急着删tar包。这时候适合做一次完整的“冒烟测试”:启动WSL,跑几个常用命令,确认环境没有明显问题。
我常用的验证清单大概是这样:
id看当前用户是否已经是原来的普通用户。cd ~ && ls -la看Home目录里的文件是否都在。- 如果有systemd服务,跑一下
systemctl status看服务状态是否正常。 - 如果有Docker后端,执行
docker info看Docker是否还能正常通信。 - 如果是开发环境,随便启动一个之前的Python或Node项目,跑一两分钟看看有没有报错。
一切正常后再决定是否删除tar包。我个人喜欢让tar包在磁盘上多躺几天,等确认没事了再删。毕竟一个tar包虽然占几个GB,但换来的是“随时能恢复”的安全感,这笔账算下来很值。
4. 迁移后的验证与细节优化
4.1 验证项目环境与VSCode Remote-WSL连接
迁移完成后,开发环境能不能无缝衔接才是真正重要的。我用VSCode写代码已经很多年了,Remote-WSL插件对我来说几乎是刚需,所以迁移后第一个要测的就是它。
做法很简单:打开VSCode,点左下角的远程连接图标,选择连接到WSL,然后打开\\wsl$\Ubuntu-22.04\home\zhangsan\projects这类路径下的项目。如果VSCode能正常识别WSL环境、打开终端、加载插件,说明整个链路没问题。
这里有个小提醒:如果之前VSCode一直连着WSL,迁移后连接不上,多半是旧会话和缓存还指向原来的位置。把所有VSCode窗口关掉,回到终端执行一次wsl --shutdown,然后重新打开VSCode,基本就能解决。
如果迁移之前用systemd管理过服务,比如自启动的数据库、Nginx、消息队列等,这一步也要逐一确认。有些发行版迁移后/etc/wsl.conf里的systemd配置可能还在,但被WSL重新注册时忽略了,导致服务没起来。检查方法就是进WSL执行systemctl list-units --type=service --state=running,看看该在的服务是不是都在。
4.2 确认C盘空间真的释放了
迁移的最终目的是救C盘,那就要验证C盘空间是不是真的还回来了。
最简单的办法是看磁盘可用空间。迁移之前记录一下C盘可用空间,注销旧发行版之后再对比。正常情况下,你会看到复用空间凭空多出好几个GB,这说明原有虚拟磁盘文件已经被清掉了。
如果空间没变化,先去检查那个经典的路径:
C:\Users\<你的用户名>\AppData\Local\Packages\...\LocalState看看ext4.vhdx是否还躺在那。如果文件还在,多半是注销时没有完全清理,可以手动删除,但前提是确认当前没有其他发行版正在使用同一个虚拟磁盘文件。
如果文件已经不在了但空间仍然不足,那C盘的压力来源就不只是WSL了,得去看Windows更新缓存、临时文件、浏览器缓存这些老对手。这不是本文的主角,但既然C盘都红了,顺手清理一下也合理。
4.3 顺手做个磁盘“瘦身”,避免虚拟磁盘虚胖
WSL2的虚拟磁盘默认是动态扩展的:写入数据的时候会变大,删除数据之后却不一定会缩小。这就是很多人发现“在WSL里删了十几个GB文件,Windows上C盘一点没变少”的根本原因。
迁移完成后,正好适合给新盘上的vhdx做一次清理瘦身。
先进入WSL,执行一次文件系统回收:
sudo fstrim /然后回到Windows侧,以管理员身份打开PowerShell,运行diskpart:
select vdisk file="D:\WSL\Ubuntu-22.04\ext4.vhdx" attach vdisk readonly compact vdisk detach vdisk exit这套命令会把虚拟磁盘内部未使用的空间“压缩”掉,让vhdx文件的实际大小变小。注意顺序不要搞错,先attach再compact,最后detach。整个过程很快,但如果你的WSL还在运行,diskpart会拒绝attach,需要先wsl --shutdown。
需要说明的是,如果在迁移前tar导出之前就已经做过类似的瘦身,那导入后新vhdx一般还很紧凑,这一步可以跳过。但如果你发现在WSL里删过大文件、或者跑过Docker后又清过镜像,这个瘦身操作就很有必要。
4.4 反向迁移与多发行版管理
这套导出导入的思路,其实不只适用于“从C盘搬到D盘”,它是一个通用的WSL迁移和备份方案。
如果你以后又装了新发行版,或者想把某个发行版从D盘再挪到E盘,甚至搬到另一台电脑上,命令流程一模一样:导出tar、拷贝到目标机器、导入。多发行版之间互不干扰,只要名字不重复就行。
这里提一句,如果你在WSL里装过体积特别大的组件,比如CUDA工具链、ClickHouse这类数据服务环境,迁移之后建议单独检查一下这些组件的路径和数据目录权限。因为整体打包时,它们的可执行文件和库文件一般能保留,但某些符号链接或者权限位在导出导入过程中有可能发生变化,出问题时优先看/usr/local/cuda或者数据库数据目录的属主和软链接状态。逻辑跟整机迁移类似,先导出、后落地、再验证。
5. 常见问题排查与避坑清单
5.1 高频报错,一张表说清楚
迁移WSL这个事,网上教程不少,但真操作时总会遇到一些报错。把常见的几个整理成一张速查表,方便对着排查。
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
| 导出时报 “The requested operation was unsuccessful” | WSL虚拟机还在运行,或目标路径权限有问题 | 先执行wsl --shutdown再重试;确认tar路径可写 |
| 导入后启动报 “Cannot find the specified file” | 导入目录不存在,或路径有中文/空格 | 检查D:\WSL\Ubuntu-22.04是否存在,重新执行--import |
| 导入后默认用户变成了root | 缺少默认用户映射 | 修改/etc/wsl.conf加[user] default=用户名,或用wsl --manage设默认用户 |
| 注销后C盘空间没变化 | 文件被占用,或系统索引未刷新 | 等待几分钟、重启资源管理器,确认ext4.vhdx已删除;必要时重启电脑 |
| systemd服务起不来 | WSL版本不支持,或/etc/wsl.conf中systemd=true没配置 | 升级WSL,在wsl.conf中加入[boot] systemd=true,执行wsl --shutdown |
| VSCode连不上WSL | 旧会话缓存指向原路径 | 关闭所有VSCode窗口,执行wsl --shutdown,重新打开VSCode |
| 导入后原先的数据库连不上 | 数据目录权限或符号链接变化 | 检查数据库数据目录的所有者,用chown修复;查看服务日志定位具体原因 |
wsl --update下载很慢 | 网络环境因素 | 耐心等待,或去官网下载离线安装包手动更新 |
这张表里我标出来的问题,都是我或者身边同事实际踩过、并且成功解决的。大部分坑的根源都逃不过“路径不对”“没关干净”“权限缺失”这三类,定位思路比背命令更重要。
5.2 迁移过程中的硬性避坑清单
这些是我在多次迁移后总结出来的规矩,写在这里当成清单,动手前扫一眼:
- 不要在WSL运行中直接拖拽或复制vhdx文件。要操作虚拟磁盘之前,先执行
wsl --shutdown,这一步任何情况都不能省。 - 不要用中文路径或带空格的目录名。Windows路径和WSL路径的解析在这类场景下特别容易出幺蛾子,纯英文最省事。
- 不要忽略tar包的体积校验。导出完看一眼文件大小,如果小得离谱,先去找原因,不要急着注销旧发行版。
- 不要在导出完成后立刻删tar包。等个几天,确认环境稳定了再删。
- 不要同时迁移多个发行版。一次处理一个,专注且安全。
这几条看着简单,但每一条背后都有过真实事故。特别是“不关WSL就操作vhdx”这条,一旦导致虚拟磁盘损坏,恢复成本会高到让你怀疑人生。
5.3 迁移完成后还能顺手做的事
迁移本身解决的是“C盘爆炸”的问题,但既然都折腾到这一步了,完全可以顺手做点锦上添花的事。
首先,给WSL配置一个更好用的终端字体。我自己比较喜欢JetBrains Mono和Cascadia Code,配合WSL默认的Git Bash主题,代码显示的清晰度和美观度会提升一大截。字体设置的位置在Windows Terminal的配置文件里,或者VSCode的设置里指定editor.fontFamily和terminal.integrated.fontFamily,体验非常接近在macOS上敲代码的感觉,这是很多WSL用户忽略的细节。
其次,把/etc/wsl.conf里的常用配置一次性配好。比如我之前提到过的默认用户、systemd开关,还可以顺手把[network]段的DNS配置看看,避免迁移后偶尔出现的域名解析问题。配置完再执行一次wsl --shutdown让配置生效。
最后,养成定期导出的习惯。我现在的做法是每季度给主力WSL发行版做一次tar备份,放到外置盘上。平时这堆tar包不占多少存在感,但哪天真出了意外,它能帮你省下一天的重装环境时间。
我前后给几台电脑做过WSL迁移,第一次动手之前也担心环境崩掉,后来发现只要导出的tar包在手,整个过程容错率其实很高。按这套流程走完,C盘通常能腾出十几个GB的空间,WSL本体放到大容量SSD上反而更从容。最后分享一个小习惯:每次改动WSL或者安装大型环境之前,顺手导出一份tar放到备用盘上,不占太多地方,但真出问题时能救命。希望这篇分享能帮你顺利把WSL搬进新家,C盘终于可以松一口气了。