Skip to content

掛載遷移:容器資料怎麼放到外接磁碟 ​

一句話結論

~/Library/Containers/ 和 ~/Library/Group Containers/ 裡的資料(微信聊天記錄、QQ 音樂快取、App Store 應用程式的資料)不能用符號連結搬走。AppPorts 1.9.0 起改為:在外接磁碟上建立一個專用的 APFS 資料卷宗,把資料複製進去,再把這個卷宗掛載到原來的目錄上。應用程式看到的路徑沒變,簽名沒動。

前提三條:外接磁碟是未加密的 APFS;第一次開啟應用程式時,在授權對話框中按一下「允許」;開啟應用程式前先連接外接磁碟。

什麼時候會用到 ​

在「資料目錄」→「應用程式資料」裡選取一個應用程式,Containers 和 Group Containers 群組下的目錄,按鈕是「掛載遷移」而不是「遷移」。其他群組(Application Support、快取等)和工具目錄、自訂目錄照舊用符號連結遷移,不受影響。

為什麼容器目錄特殊、為什麼不看主程式是不是沙盒,見容器資料、沙盒與簽名身分。

按一下「掛載遷移」之後 ​

AppPorts 先唯讀檢查一次外接儲存裝置,不改動任何東西,再按結果給出下一步:

檢查結果你會看到可以怎麼做
未加密的 APFS,空間足夠遷移說明:本機能釋放多少空間、第一次開啟要按一下允許、平時要連接磁碟按一下「遷移資料」開始
exFAT、NTFS、HFS+ 等「這個外接儲存裝置是 exFAT 格式」維持現狀;選擇其他位置;檢視準備方法
加密的 APFS「這個外接儲存裝置已加密」維持現狀;改選未加密的 APFS 位置
空間不足需要多少、還剩多少清理空間後重新檢查,或選擇其他位置
沒選外接儲存裝置 / 未連接提示選擇或連接外接儲存裝置選擇外接儲存裝置、重新檢查

不能遷移時什麼都不用改。 應用程式本體、Application Support、快取、工具目錄照常可以遷移到這個磁碟,只有容器資料留在本機,應用程式照常使用。以後想遷移時,按準備 APFS 外接磁碟的方法準備好再來。

為什麼加密的 APFS 磁碟暫不支援

掛載遷移建立的資料卷宗不會繼承原卷宗的密碼。照常遷移的話,原本在本機受 FileVault 保護的聊天記錄會落在一個沒有密碼的卷宗上。自動解鎖和密碼管理完成之前,AppPorts 不做這種悄悄降級。詳見加密的外接磁碟。

遷移前 ​

  • 請先把 AppPorts 放進「應用程式」資料夾,再從那裡開啟。 登入代理需要一個持久有效的程式路徑。從下載目錄或 DMG 直接執行時,macOS 可能使用暫存的 App Translocation 路徑;偵測到這種路徑時,AppPorts 會阻止新的掛載遷移並提示安裝。移動或更新 AppPorts 後請開啟一次,讓它校準代理路徑;路徑不變時不會重新載入代理。
  • 完全退出要遷移的應用程式。 AppPorts 會檢查,正在執行時不允許遷移。
  • AppPorts 需要完整磁碟取用權限。 把卷宗掛到容器路徑這個動作本身受系統管控,沒有權限會失敗。
  • 想想備份。 和所有資料遷移一樣,重要資料建議先自行備份一份。遷移後這部分資料在外接磁碟上,而 Time Machine 通常不備份外接磁碟,需要時請在「系統設定 › 一般 › Time Machine」的選項裡確認這個磁碟在備份範圍內。

遷移過程中發生了什麼 ​

  1. 在外接磁碟的 APFS 容器裡建立一個卷宗,建好後不自動掛到 /Volumes。卷宗名稱形如 AppPorts-<Bundle ID>-<目录名>-xxxxxx,和磁碟上其他卷宗共用剩餘空間,不用指定大小。
  2. 把新卷宗暫存掛到 ~/Library/Application Support/AppPorts/mounts/ 下,用 AppPorts 的複製器把目錄內容複製進去,在卷宗根目錄寫一個 .appports-mount-metadata.plist 標記,然後卸載。
  3. 把原目錄改名為同一卷宗上的安全備份,在原路徑建立一個空目錄,把卷宗掛上去,驗證掛上的確實是這個卷宗。
  4. 寫入掛載記錄 ~/Library/Application Support/AppPorts/container-mounts.plist,安裝登入時自動重掛的代理,最後刪除安全備份。

外接磁碟空間不夠時,在建立卷宗之前就停下。遷移尚未完成就失敗時,AppPorts 會嘗試回復原狀;若無法安全完成,會保留副本並說明保留路徑。

如果遷移已經完成,只是最後清理本機安全備份失敗,掛載的資料仍可正常使用。AppPorts 會明確顯示尚未清理的備份路徑,不必重新遷移。

遷移完成後,mount 命令能看到卷宗直接掛在容器路徑上:

/dev/disk7s5 on /Users/<user>/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files (apfs, local, nodev, nosuid, journaled, noowners, nobrowse)

遷移後第一次開啟應用程式 ​

系統會詢問是否允許應用程式取用可移除式卷宗上的檔案,請按一下**「允許」**。這是 macOS 對資料落在外接磁碟上的正常檢查,只彈一次。

按了拒絕,應用程式會當作沒有資料,顯示空白。補救:系統設定 → 隱私權與安全性 → 檔案與資料夾(或「可移除式卷宗」),找到該應用程式開啟開關,或者在終端執行 tccutil reset SystemPolicyRemovableVolumes <Bundle ID> 讓它下次重新詢問。

/System/Applications 下的系統應用程式不會顯示授權對話框,直接靜默拒絕。AppPorts 本來就不遷移它們。

日常使用 ​

開啟應用程式前先連接外接磁碟。 磁碟未連接時,掛載點只是一個被鎖住的空目錄(權限 000),應用程式會看到空資料,不會報錯,也不會把新資料寫到本機形成兩份。連上外接磁碟後 AppPorts 會自動把卷宗接回來,資料就回來了。

Finder 裡平時看不到這些資料卷宗。 AppPorts 掛載時帶 nobrowse 選項,資料卷宗不出現在 Finder 側邊欄和桌面。外接磁碟剛接入的一兩秒內,macOS 可能先把卷宗自動掛到 /Volumes 並短暫顯示圖示,AppPorts 接回後就會消失。用早期版本遷移、目前仍顯示在 Finder 裡的卷宗,AppPorts 下次啟動或外接磁碟下次接入時會在原位置隱藏,不需要卸載重掛。「磁碟工具程式」裡仍能看到名為 AppPorts-… 的卷宗,不要在那裡清除或刪除它們,那就是遷移過去的資料。

拔除磁碟前先退出應用程式,再在 AppPorts 裡按一下「卸載」或在 Finder 裡退出外接磁碟。 直接拔除磁碟的話,最後幾秒鐘的寫入可能遺失,資料庫檔案可能需要修復;我們做過拔除磁碟測試,APFS 卷宗這種情況下遺失的只是最後幾個交易,見實驗紀錄:拔除磁碟測試。

什麼時候自動接回:

  • AppPorts 執行時:啟動時以及每次有卷宗接入系統時,自動把線上但沒掛載的記錄掛回去。
  • 沒開 AppPorts 時:遷移成功後 AppPorts 會安裝一個登入代理,登入時以及每次外接磁碟接入時靜默掛回,然後退出。最後一條記錄還原後,代理會自動移除。
  • 開機後立刻開啟應用程式,仍可能讀到十幾秒的空目錄(系統把登入代理排在登入項之後啟動),退出應用程式再開啟即可。確保資料安全的關鍵是掛載點一直保持為空:應用程式就算先起來了,也唯讀到空目錄,不會把新資料寫到本機形成分叉,等卷宗掛回來自己就恢復了(微信實測三次都能恢復)。

macOS 12 等舊系統需要輸入管理者密碼

macOS 27 允許一般使用者把卷宗掛到自己目錄下的路徑;macOS 12 實測不允許。AppPorts 遇到這個錯誤會顯示系統的管理者密碼對話框重試,一次遷移通常只問一次。登入代理沒有介面,無法顯示密碼對話框,所以在這類系統上登入後不能自動重掛,需要開啟 AppPorts(它會提示輸密碼)或在「應用程式資料」頁手動按一下「掛載」。13 到 26 之間從哪一版開始放開,還沒有逐一驗證。

狀態與操作 ​

狀態意義可用操作
已掛載卷宗掛在原目錄上,應用程式正常讀寫卸載、還原
待掛載卷宗線上但沒掛載(剛連接磁碟、或手動卸載過)掛載、還原
外接磁碟未連接找不到這個資料卷宗,多半是外接磁碟未連接連上外接磁碟,AppPorts 會自動接回;已經連接仍顯示時,見下方排查

還原會把卷宗上的資料複製回本機,然後刪除卷宗和記錄,外接磁碟要保持連接:

  • 開始前檢查本機剩餘空間,不夠時直接停下,卷宗和記錄原樣保留。
  • 複製完成後,AppPorts 先把掛載記錄轉為待清理資訊,防止自動重掛,再切換回本機目錄。它只刪除卸載後留下的空掛載點,不會遞迴刪除任何目錄。
  • 如果切換回本機目錄尚未完成,暫存的本機副本和外接卷宗都會保留。本機副本仍在同一目錄下名為 .appports-restore-staging-… 的隱藏資料夾裡;請依 AppPorts 顯示的保留路徑與提示處理。
  • 如果本機目錄已經還原,只是刪除外接卷宗或更新清理記錄失敗,AppPorts 會明確提示還原完成但清理尚未完成。可在資料目錄頁重試清理,不要重複遷移或還原。

無法確認副本是否仍在時,可選擇「僅移除清理記錄」;這不會刪除本機備份或外接卷宗,也不會重新掛載,仍存在的副本需自行清理。

如果掛載點目錄裡出現了本機檔案(比如應用程式在磁碟未連接時想辦法寫了東西),AppPorts 會拒絕在上面掛載,免得蓋住這份資料。把檔案移走再掛載。

移除或移動 AppPorts 之前 ​

掛載遷移靠 AppPorts 的登入代理在每次登入後把卷宗接回來。刪除 AppPorts 之前,先在「應用程式資料」裡把掛載遷移的目錄「還原」回本機。 不還原就刪除 AppPorts 的話,資料仍完好地留在外接卷宗上,但登入後沒人把它接回來,應用程式會看到空目錄;重新安裝 AppPorts 並開啟一次即可恢復。

只是更新或移動 AppPorts 的話,開啟一次新版 AppPorts即可,它會自動把代理指向新的程式位置。

排查 ​

現象處理
狀態是「外接磁碟未連接」,但磁碟已經連接在「磁碟工具程式」裡確認外接磁碟上還有 AppPorts-… 的卷宗。卷宗還在:按一下 AppPorts 工具列的重新整理按鈕,或重新插拔一次外接磁碟。卷宗已被刪除:這個目錄的資料已經不在外接磁碟上,只能從備份恢復
應用程式開啟後是空的先看該目錄是不是「已掛載」;不是就連上外接磁碟或按一下「掛載」。是「已掛載」仍為空,檢查第一次開啟應用程式時有沒有按了拒絕
按一下「掛載」提示掛載點不為空掛載點目錄裡有本機檔案。確認這些檔案是什麼,把它們移走後再掛載
遷移或還原提示背景正在連接外接儲存裝置登入代理正在掛載,稍等幾秒再試一次

為什麼不用磁碟映像檔 ​

exFAT 使用者不少,我們認真試過在 exFAT 磁碟上放一個 APFS 磁碟映像檔(sparsebundle)再掛載的辦法。它不彈授權對話框、效能相當、任何格式都能放,看起來更好。

然後做了拔除磁碟測試:寫入資料的時候直接拔 USB 隨身碟。APFS 卷宗只遺失最後幾個交易,資料庫能修復;磁碟映像檔兩輪都整個打不開,裡面的資料全部失聯。原因是映像檔自己的"目錄簿"每隔幾秒重寫一次,拔除磁碟正好撞上寫一半,整個映像檔就成了沒有目錄的碎片。完整資料見實驗紀錄:拔除磁碟測試,面向使用者的解釋見為什麼外接磁碟必須是 APFS。

所以只支援 APFS 卷宗。

技術細節 ​

自動重掛的時序 ​

  • 登入代理是 ~/Library/LaunchAgents/com.shimoko.AppPorts.container-mount.plist,執行 AppPorts --mount-agent。它同時監聽 /Volumes:外接磁碟一掛上系統就再跑一次。實測這次開機(2026-09-22)的順序是「登入完成 → 4.6 秒後代理啟動 → 18 秒後兩個卷宗掛回容器路徑」,比早先版本快了約 19 秒,但登入項裡的應用程式約 3 秒就起來了。時間線和為什麼不能更早,見實驗紀錄:開機前掛載。
  • 磁碟遲遲未出現時,代理不會只試一遍就走:它在行程內監聽 /Volumes,等下一次真實變化再試,而不是按固定間隔輪詢 —— 開機時系統很忙,外接磁碟可能好幾分鐘後才被辨識(實測 2026-09-23 那次是開機後 2 分 33 秒),定時輪詢要麼在最忙的時候空轉 diskutil,要麼錯過應用程式啟動。等不到事件時每 20 秒補做一次檢查,總等待時間 180 秒;等卷宗期間不佔鎖。實測:卷宗出現到掛載完成約 1 秒。
  • 掛載前先看一眼 /Volumes/<卷名>:開機和連接磁碟時系統幾乎總是先把卷宗掛到那裡,用 statfs 加一次卷宗根目錄標記讀取(微秒級)就能確認是不是我們的卷宗,省掉一次 diskutil info —— 2026-09-23 開機實測那次查詢花了 9 秒(登入後系統正忙),是整個流程中最耗時的一步。認不出來(卷宗名稱被系統改名、標記缺失)才退回 diskutil 查詢。
  • 掛載之後要驗證:diskutil mount -mountPoint 有個需要注意的行為 —— 卷宗已經被系統掛上時(開機/連接磁碟時 macOS 常搶先把它掛到 /Volumes),它會忽略掛載點參數、照樣輸出 mounted 並回傳 0。所以每次掛載後都確認卷宗真的落在目標路徑上;沒落到位就重新查一次卷宗掛在哪,把它從 /Volumes 卸下來再掛(最多 3 輪)。2026-09-21 和 09-23 各出過一次這種情況,當時判定為失敗並放棄,微信隨後讀到空目錄。
  • 只動自己的卷宗:掛載、卸載、還原之前都核對掛載點上的 Volume UUID 是否與記錄一致;路徑上掛著別的卷宗時直接停下,不會卸載、覆蓋或刪除它。
  • 代理和 AppPorts 共用一把跨行程鎖(~/Library/Application Support/AppPorts/operation.lock):AppPorts 正在做掛載遷移、卸載或還原時,代理會先讓路(最多等 120 秒),等不到就跳過這一輪,留到下次連接磁碟或下次登入。反過來,AppPorts 拿不到鎖時不會開始操作,只提示稍後重試。鎖只在每一輪掛載動作期間持有 —— 代理等卷宗的那幾分鐘不佔鎖,不會卡住你在 AppPorts 裡的操作。
  • 遷移記錄檔案讀不出來時,AppPorts 不會把它當成空記錄覆蓋寫入,而是保留原檔案並拒絕新增或刪除記錄。
  • 不用 /etc/fstab:實測 UUID= 形式掛不上,裝置號形式插拔後會變,而且開機由 root 掛載同樣受權限管控。

卷宗上的 Spotlight 索引 ​

系統會把掛在容器路徑上的卷宗當成一般外接卷宗,給它建一份自己的索引。實測兩個微信卷宗的 .Spotlight-V100 合計 110 MB,而且開機後還在重寫。這些是應用程式資料,系統索引沒有任何用處,所以:

  • 建立卷宗後往卷宗根目錄寫一個空的 .metadata_never_index,mds 會跳過整個卷宗;寫入時如果系統已經建好 .Spotlight-V100,一併刪掉。
  • 標記跟著卷宗走:更換連接位置、還原掛載遷移都不用重做。
  • 在這個版本之前遷移過的卷宗,下次掛載時自動補上標記。
  • 標記不寫回本機目錄:還原時 .metadata_never_index 和 .fseventsd、.Spotlight-V100 一樣被跳過。

自查命令 ​

bash
# 挂载记录
plutil -p ~/Library/Application\ Support/AppPorts/container-mounts.plist

# 当前挂载
mount | grep Containers

# 登录代理
launchctl print gui/$(id -u)/com.shimoko.AppPorts.container-mount

# 卷根有没有防索引标记;系统的索引状态应为 Indexing disabled
ls -la "<挂载点路径>/.metadata_never_index"
mdutil -s "<挂载点路径>"

# 手动重挂(要在有完全磁盘访问权限的终端里执行;旧系统前面加 sudo)
diskutil mount nobrowse -mountPoint "<挂载点路径>" <Volume UUID>

相關文件 ​

最近更新