「業務應用讀不了存在桌面上的 CSV。」「換電腦之後,以前能用的匯入以『找不到檔案』失敗。」「檔案總管看得到檔案,從應用開啟卻出錯。」── 這幾年,這類來自客戶的諮詢已成定番。
調查之後,原因往往不是應用程式錯誤,而是 OneDrive 的「桌面與文件自動備份」(已知資料夾搬移,KFM)與「隨選檔案」。真正的桌面已搬到 C:\Users\<名稱>\OneDrive\Desktop,你在那裡看到的檔案有一部分是沒有本機內容的「預留位置」。使用者和 IT 都沒注意到這項變化,繼續用這台電腦。
換句話說,業務應用「檔案在本機磁碟上」的隱含前提,在沒有人做決定的情況下,已被「檔案在雲端,本機只有外表」這個前提取代。本文以中小企業的資訊系統人員與 Windows 應用開發者為對象,依 Microsoft Learn 一手資料整理預留位置如何運作、如何從檔案屬性判斷狀態、業務應用踩到的典型陷阱、開發端與 IT 端各自能做的事,以及接到「檔案打不開」時的分診程序。
flowchart TB
accTitle: 業務應用隱含前提的替換
accDescr: 檔案在本機磁碟上這個業務應用的隱含前提,在沒有人做決定的情況下,已被實體在雲端、本機只有外表這個前提取代
before["以往的隱含前提"] --> b1["實體在本機磁碟上"]
after["被取代後的前提"] --> a1["實體在雲端"]
a1 --> a2["本機只有外表"]
a2 -.-> note["預留位置"]
圖 1: 「實體在本機」這個前提,在沒有人做決定的情況下,已被「實體在雲端,本機只有外表」取代。
1. 先講結論
- 桌面、文件、圖片可能已被 KFM 搬到
C:\Users\<名稱>\OneDrive\底下。 新電腦初始設定時很容易被打開,組織也能用原則一次套用。假設固定路徑的應用會在這裡壞掉。1 - 目前的同步應用預設開啟隨選檔案。 在其他裝置或網頁上建立的檔案,會以沒有本機內容的「僅限線上」預留位置出現。23
- 預留位置的真正身分是 Cloud Files API 管理的重新分析點(cldflt.sys 迷你篩選器)。 對檔案總管與檔案 API 都像普通檔案,開啟就會自動下載(補水)。4
- 狀態可從檔案屬性判斷。 FILE_ATTRIBUTE_OFFLINE、RECALL_ON_DATA_ACCESS、PINNED、UNPINNED 等是標記,attrib 指令以 O、P、U 字母顯示。只檢查屬性不會引發下載。567
- 業務應用的典型事故是「打不開」、「變慢」、「誤判屬性」、「監視事件風暴」、「與同步衝突」的組合。 離線或 OneDrive 停止時補水失敗,批次處理會誘發每個檔案的下載。48
- 應用端的對應是「尊重預留位置」。 基本做法是列舉時用屬性判斷、不要輕易開啟,必要時用 FILE_FLAG_OPEN_NO_RECALL,不要把資料夾放在 OneDrive 底下。910
- IT 端的對應是「用釘選營運」與「用原則控制」。 用「一律保留在此裝置上」為業務資料夾保證實體,並用群組原則 / Intune 刻意設定 KFM 與隨選檔案。別忘了儲存感知也能「把未使用的檔案退回僅限線上」。1112
一句話:「檔案總管看得到的檔案」與「本機磁碟上有實體的檔案」已不再是同一件事。
2. 正在發生什麼 ── KFM 與隨選檔案
2.1. 桌面可能已不是 C:\Users\<名稱>\Desktop
OneDrive 同步應用有一項稱為已知資料夾搬移(KFM)的功能。設定畫面顯示為「備份」、「備份重要資料夾」等;開啟後,真正的桌面、文件、圖片會被搬移(重新導向)到 OneDrive 資料夾底下。1
| 使用者看到的位置 | KFM 前的實際路徑 | KFM 後的實際路徑 |
|---|---|---|
| 桌面 | C:\Users\taro\Desktop |
C:\Users\taro\OneDrive\Desktop |
| 文件 | C:\Users\taro\Documents |
C:\Users\taro\OneDrive\Documents |
| 圖片 | C:\Users\taro\Pictures |
C:\Users\taro\OneDrive\Pictures |
新電腦初始設定(OOBE)以 Microsoft 帳戶或公司帳戶登入時,資料夾備份常被當成預設提案,照著往下走就會開啟。組織也能用「以無訊息方式將 Windows 已知資料夾移到 OneDrive」原則(KFMSilentOptIn)不問使用者就一次套用。111
flowchart TB
accTitle: KFM 被開啟的兩條路徑
accDescr: 新電腦初始設定以帳戶登入時,資料夾備份會被當成預設提案,照著往下走就會開啟;在組織裡 KFMSilentOptIn 原則會不問使用者就一次套用
oobe["新電腦的初始設定"] --> signin["以帳戶登入"]
signin --> prompt["預設提出備份"]
prompt --> on1["照著往下走就開啟"]
org["組織原則"] --> silent["KFMSilentOptIn"]
silent --> on2["不問使用者就一次套用"]
on1 --> kfm["KFM 開啟"]
on2 --> kfm
圖 2: KFM 會在沒人注意的情況下開啟,來源是初始設定的預設提案,或組織的無訊息套用原則。
尷尬之處在於 檔案總管的外表幾乎不變。殼層已知資料夾 API(SHGetKnownFolderPath 與 .NET 的 Environment.GetFolderPath)會回傳搬移後的正確路徑,所以守規矩的應用會繼續運作。壞掉的是 在設定檔或程式碼裡寫死 C:\Users\%USERNAME%\Desktop 這類固定路徑的應用。換電腦後匯入以「找不到檔案」失敗的典型模式就是這個。
flowchart TB
accTitle: KFM 之後應用如何解析路徑
accDescr: KFM 把真正的桌面等資料夾搬到 OneDrive 底下後,使用已知資料夾 API 的應用會以搬移後的正確路徑繼續運作,但寫死固定路徑的應用會找不到檔案
kfm["KFM 已開啟"] --> move["真正的桌面等搬到 OneDrive 底下"]
move --> how{"應用如何解析路徑?"}
how -->|已知資料夾 API| ok["取得搬移後的正確路徑並繼續運作"]
how -->|寫死的固定路徑| ng["找不到檔案"]
圖 3: KFM 之後,使用已知資料夾 API 的應用會繼續運作,但寫死固定路徑的應用會在這裡壞掉。
2.2. 隨選檔案 ── 看得到,但沒有實體
另一條線索是隨選檔案。在開啟的環境裡,OneDrive 上的每個檔案都在檔案總管裡看得到,但 內容要等到檔案被開啟才下載。這項功能在目前的同步應用裡預設開啟,Microsoft 也建議維持開啟。23
狀態可從檔案總管的狀態圖示分辨。13
| 圖示 | 狀態 | 本機內容 |
|---|---|---|
| 雲朵標記 | 僅限線上 | 無(只有預留位置) |
| 白底勾選 | 本機可用 | 有(之後可能被自動釋放) |
| 綠底白勾 | 一律保留在此裝置上(釘選) | 有(不在自動釋放範圍) |
這裡重要的是中間狀態。開過一次、已有本機內容的檔案,可能因使用者的「釋放空間」或稍後會談到的儲存感知 再變回僅限線上。這是「上個月還能用」這類難以重現故障的原因之一。312
stateDiagram-v2
accTitle: 隨選檔案的三種狀態與轉換
accDescr: 僅限線上的檔案開啟後會變成本機可用,但釋放空間或儲存感知可把它退回僅限線上,只有釘選的檔案不在自動釋放範圍內
s1: 僅限線上(雲朵標記)
s2: 本機可用
s3: 釘選(一律保留在此裝置上)
s1 --> s2: 開啟(補水)
s2 --> s1: 釋放空間
s2 --> s1: 儲存感知
s1 --> s3: 一律保留在此裝置上
s2 --> s3: 一律保留在此裝置上
s3 --> s2: 取消釘選
圖 4: 隨選檔案的三種狀態。「本機可用」可能自動退回僅限線上;釘選不在該範圍內。
3. 預留位置的真正身分 ── Cloud Files API 與重新分析點
隨選檔案實作在 Windows 10 版本 1709 引入的 OS 機制 Cloud Files API 之上。檔案系統端的工作單位是名為 cldflt.sys 的檔案系統迷你篩選器(服務名稱 CldFlt,「Windows Cloud Files Filter Driver」),OneDrive 是使用此 API 的「同步提供者」之一。47
預留位置在技術上是 重新分析點。檔案系統上只有檔名、大小、時間戳等中繼資料(約 1KB),沒有內容資料。應用開啟檔案並讀取時,迷你篩選器偵測到要求,指示同步提供者傳輸資料,等下載完成後讀取才繼續。這次擷取稱為 補水(hydration);丟掉本機內容、回到預留位置稱為 脫水(dehydration)。4
sequenceDiagram
accTitle: 開啟預留位置時的補水
accDescr: 應用開啟預留位置並讀取時,cldflt.sys 迷你篩選器偵測要求,指示同步提供者傳輸資料,等下載完成後讀取才繼續
participant app as 業務應用
participant flt as cldflt.sys 迷你篩選器
participant sync as 同步提供者
app->>flt: 開啟並讀取的要求
flt->>sync: 指示資料傳輸
sync-->>flt: 下載完成
flt-->>app: 讀取繼續
圖 5: 預留位置的讀取,是在迷你篩選器讓同步提供者抓回資料之後才繼續。
聽到「重新分析點」會擔心與「偵測到重新分析點就特別處理」的既有程式碼相容,但為了相容,Cloud Files API 對同步引擎與 %systemroot% 底下以外的所有人隱藏它是重新分析點這件事。對普通應用來說,它看起來像「只是開啟稍微慢一點的普通檔案」。這種徹底的透明既方便,也是「應用在沒注意到的情況下被打破前提」的原因。4 重新分析點本身的機制在「NTFS 內部結構」說明。
flowchart TB
accTitle: 隱藏重新分析點,以及看起來的差異
accDescr: 預留位置的真正身分是重新分析點,但 Cloud Files API 對同步引擎以外的程序隱藏此事,因此對普通應用看起來只是開啟稍微慢一點的普通檔案
ph["預留位置(重新分析點)"] --> who{"是哪個程序開啟的?"}
who -->|同步引擎等| raw["可見為重新分析點"]
who -->|其他應用| plain["看起來像普通檔案"]
plain -.-> note["看起來只是開啟稍慢"]
圖 6: 它是重新分析點這件事對同步引擎以外的所有人隱藏,對普通應用看起來像普通檔案。
在檔案總管內容中,預留位置的特徵是 「大小」顯示原始大小,而「磁碟上的大小」幾乎是 0。「有大小,所以一定有實體」這個假設在這裡不成立。
flowchart TB
accTitle: 預留位置在內容中的樣子
accDescr: 在檔案總管內容中,預留位置的大小顯示原始大小,磁碟上的大小幾乎是 0,因此有大小就一定有實體的假設不成立
prop["預留位置內容"] --> size["大小是原始大小"]
prop --> disk["磁碟上的大小幾乎是 0"]
size -.-> trap["一定有實體的假設"]
disk -.-> truth["沒有本機內容"]
圖 7: 預留位置的「大小」顯示原始大小,而「磁碟上的大小」幾乎是 0。
4. 檔案屬性會告訴你狀態
預留位置狀態以普通檔案屬性公開。主要如下。5
| 屬性 | 值 | 意義 |
|---|---|---|
| FILE_ATTRIBUTE_OFFLINE | 0x00001000 | 資料無法立即使用(階層式儲存管理的傳統屬性) |
| FILE_ATTRIBUTE_RECALL_ON_OPEN | 0x00040000 | 沒有實體本機內容。只出現在目錄列舉結果 |
| FILE_ATTRIBUTE_PINNED | 0x00080000 | 使用者意圖「一律留在本機」(釘選) |
| FILE_ATTRIBUTE_UNPINNED | 0x00100000 | 不必保留本機內容(改成僅限線上的意圖) |
| FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS | 0x00400000 | 部分或全部內容不在本機。讀取會從遠端擷取 |
命令提示字元的 attrib 指令可用單一字母顯示與設定這些屬性。O 是離線屬性,P 是釘選,U 是取消釘選。6 與 OneDrive 隨選檔案狀態的對應,Microsoft 文件整理如下。7
| 隨選檔案狀態 | 屬性 | 設定指令 |
|---|---|---|
| 一律可用(釘選) | Pinned(顯示 P) | attrib +p <path> |
| 本機可用 | 既非 P 也非 U | attrib -p <path> |
| 僅限線上 | Unpinned(顯示 U) | attrib +u <path> |
有一點要注意。切換狀態有順序。 想把僅限線上(U)的檔案變成「本機可用」時,只跑 -p 會留下 U,實體不會被抓回來。Microsoft 文件也示範先做 +p(一律可用)下載實體,再做 -p 的程序。7 在必須可靠切換既有狀態的指令碼裡,較安全的做法是像 attrib +p -u 這樣 同時清掉相反屬性。
flowchart TB
accTitle: 從僅限線上切到本機可用的順序
accDescr: 對僅限線上的檔案只執行 attrib -p 會留下 U 屬性且不會抓回實體;需要先用 attrib +p 下載實體再做 -p
u["僅限線上(U)"] -->|只做 attrib -p| stay["維持 U;實體未被抓回"]
u -->|attrib +p| pin["釘選(下載實體)"]
pin -->|attrib -p| local["本機可用"]
圖 8: 從僅限線上切換,需要先用 +p 抓回實體,再做 -p 的順序。
PowerShell 判斷的例子。只看屬性不會引發補水,因此可放心用於調查與批次檢查。
function Test-CloudPlaceholder {
param([Parameter(Mandatory)][string]$Path)
$value = [int](Get-Item -LiteralPath $Path -Force).Attributes
[pscustomobject]@{
Path = $Path
Offline = ($value -band 0x00001000) -ne 0 # FILE_ATTRIBUTE_OFFLINE
RecallOnDataAccess = ($value -band 0x00400000) -ne 0 # 內容並非全部在本機
Pinned = ($value -band 0x00080000) -ne 0 # 一律保留在此裝置上
Unpinned = ($value -band 0x00100000) -ne 0 # 僅限線上
}
}
# 批次檢查文件資料夾底下的 CSV(不會下載內容)。
# 用已知資料夾 API 解析路徑。把顯示名稱
# "Documents" 寫死,可能因實際資料夾名稱
# (Documents 對上當地語系名稱)與 KFM 設定
# 而變成不存在的路徑
Get-ChildItem ([Environment]::GetFolderPath('MyDocuments')) -Recurse -Filter *.csv |
ForEach-Object { Test-CloudPlaceholder $_.FullName } |
Where-Object RecallOnDataAccess |
Format-Table -AutoSize
轉成 [int] 是因為 .NET 的 FileAttributes 列舉沒有定義 RECALL_ON_DATA_ACCESS 這類名稱。對數值做位元運算就能順利判斷。
5. 業務應用踩到的陷阱
這是本題。預留位置的透明大多數時候很方便,但與典型業務應用處理模式疊在一起,會以以下六種形狀浮現。
5.1. 開啟就立刻開始下載 ── 離線時「打不開」
開啟僅限線上的檔案會當場開始補水。線上、檔案又小,快到你不會注意到,但 當 OneDrive 停止、登出或暫停、網路不穩、或檔案很大時,就變成「檔案存在但打不開」。錯誤可能以 ERROR_CLOUD_FILE_PROVIDER_NOT_RUNNING(0x8007016A,”The cloud file provider is not running”)這類雲端檔案系列代碼回來,也可能在應用端被觀察成逾時。8
更進一步的陷阱是,相當於 File.Exists() 的存在檢查,以及取得屬性或大小,都會成功。你會得到本機磁碟直覺解釋不了的錯誤模式:「存在檢查過了,讀取卻失敗」。
flowchart TB
accTitle: 存取僅限線上檔案時的分支
accDescr: 存在檢查與取得屬性、大小會成功,但讀取內容會開始補水;若 OneDrive 在執行且網路正常,下載後可讀,否則以 0x8007016A 等錯誤或逾時失敗
check["存在檢查,或取得屬性或大小"] --> ok1["成功"]
open["讀取內容"] --> hyd["開始補水"]
hyd --> cond{"OneDrive 在執行且網路正常?"}
cond -->|是| read["下載後可讀"]
cond -->|否| err["0x8007016A 等錯誤,或逾時"]
圖 9: 存在檢查可以成功,讀取卻失敗。成敗取決於 OneDrive 是否在執行,以及網路。
5.2. 批次處理誘發每個檔案的下載
把讀取資料夾內每個檔案的批次、雜湊計算、全文搜尋或自製備份對準 OneDrive 底下的樹,你碰到的每個檔案都會被誘發補水。對數 GB 的資料夾,處理會異常變慢,下載也會填滿磁碟,低容量電腦上空間不足會引出另一種故障。隨選檔案原本要省下的容量,一次全掃描就沒了。
此外,若應用在沒有明確使用者操作的情況下引發補水,Windows 可能顯示快顯並讓使用者選擇封鎖。一旦封鎖,該應用之後的下載會持續失敗(可在設定的「自動下載檔案」解除)。這是「只有某台電腦匯入失敗」的原因之一。4
flowchart TB
accTitle: 批次處理如何誘發每個檔案的下載
accDescr: OneDrive 底下的批次會誘發碰到的每個檔案補水,造成處理延遲與磁碟壓力,若使用者在快顯上封鎖,之後下載會持續失敗
scan["OneDrive 底下的批次"] --> touch["碰到的每個檔案都補水"]
touch --> cost["處理延遲與磁碟壓力"]
touch --> toast["可能出現快顯"]
toast --> block{"使用者封鎖了嗎?"}
block -->|是| fail["之後下載持續失敗"]
block -->|否| cont["下載繼續"]
圖 10: 批次會誘發每個檔案補水,若在快顯上被封鎖,之後失敗會持續。
5.3. 沒預期這些屬性的程式碼的誤動作
不知道 FILE_ATTRIBUTE_OFFLINE 或 RECALL_ON_DATA_ACCESS 的程式碼,會在意想不到的地方誤動作。
- 屬性用完全相等測試(
attributes == FileAttributes.Archive等),預留位置被當成「非預期檔案」排除或當錯誤處理 - 備份或同步工具的排除判斷把 OFFLINE 屬性解讀成「已送到磁帶」而略過(或反過來,把本該排除的每個檔案都抓回來)
- 唯讀檢查或封存位元操作破壞屬性組合
flowchart TB
accTitle: 沒預期屬性的程式碼的誤動作模式
accDescr: 不知道預留位置屬性的程式碼,會因完全相等屬性測試而排除或當錯誤、因誤解 OFFLINE 而略過或全抓、或因屬性操作破壞組合而誤動作
code["沒預期屬性的程式碼"] --> m1["完全相等測試"]
code --> m2["誤解 OFFLINE"]
code --> m3["屬性操作破壞組合"]
m1 --> r1["被當成非預期而排除或出錯"]
m2 --> r2["略過,或全部抓回"]
圖 11: 不知道 OFFLINE 或 RECALL 系列屬性的程式碼,會以排除、錯誤略過或屬性破壞的方式誤動作。
Microsoft 給迷你篩選器開發者的指引明白寫道:不應對帶有 RECALL_ON_DATA_ACCESS 的檔案發出輕率的讀寫。文件針對核心驅動程式,但「碰到帶此屬性的檔案內容 = 發生擷取成本」這個原則,原封不動適用於使用者模式應用。10
5.4. FileSystemWatcher 與同步的交互作用
用 FileSystemWatcher 監視 OneDrive 底下的資料夾,你得到的不只是使用者操作,還有 同步應用活動帶來的大量事件。其他裝置的變更每次同步、補水或脫水每次改變屬性或大小,都可能發出 Changed 事件。再者,把監視並匯入的結果寫回同一資料夾的設計,會在寫入 → 上傳 → 屬性更新 → 另一個事件的迴圈裡變成「變更通知風暴」。事件稀疏與實體檢查的設計見「FileSystemWatcher 的使用方法與注意事項」,但在 OneDrive 底下,這項需求又高一階。
flowchart TB
accTitle: 監視並寫回造成的變更通知迴圈
accDescr: 若收到變更事件的監視應用把匯入結果寫回同一資料夾,同步應用的上傳與屬性更新會再發出事件,形成變更通知風暴的迴圈
ev["變更事件"] --> proc["監視應用匯入"]
proc --> write["寫回同一資料夾"]
write --> up["同步應用上傳"]
up --> attr["屬性或大小被更新"]
attr --> ev
sync["其他裝置變更的同步"] -.-> ev
圖 12: 把匯入結果寫回同一資料夾,會變成同步應用活動再產生事件的迴圈。
5.5. 獨占鎖定期間的同步衝突,以及「複本」檔案
業務應用以獨占鎖定開啟檔案期間,同步應用無法上傳或更新該檔案。把長時間持鎖的應用(Access .accdb、自製格式資料檔、記錄檔等)放在 OneDrive 底下,同步錯誤會變成常態。反過來說,同一檔案在多台電腦上編輯時,同步應用會試著兩邊都留,並產生帶電腦名稱的重複檔,或「— 複本」這類衝突複本。假設「一個資料夾、一個檔案」的匯入會在這份重複上誤動作。鎖定設計的基礎見「檔案整合的互斥控制基礎」。
flowchart TB
accTitle: 獨占鎖定與多機編輯造成的同步問題
accDescr: 應用以獨占鎖定開啟檔案期間同步應用無法更新,同步錯誤變成常態;同一檔案在多台電腦編輯會產生衝突複本,一個資料夾一個檔案的假設崩解
lock["應用以獨占鎖定開啟"] --> nosync["無法同步;同步錯誤成常態"]
multi["同一檔案在多台電腦編輯"] --> conflict["產生衝突複本"]
conflict --> dup["帶電腦名稱或複本的重複"]
dup --> bad["一個資料夾一個檔案的假設崩解"]
圖 13: 獨占鎖定讓同步錯誤成常態,多台電腦編輯則因衝突複本引出誤動作。
5.6. 防毒與搜尋索引器誘發補水
讀取檔案內容的不只是業務應用。防毒軟體的完整掃描與搜尋索引器,只要碰到預留位置的內容也會誘發補水。Microsoft Defender 等產品在隨選掃描時會略過帶 RECALL_ON_DATA_ACCESS 屬性的檔案,但那是產品端的對應,不能假設每個安全性產品都會同樣小心。若看到「每晚掃描時網路與磁碟都被打滿」或「本該僅限線上的檔案到早上已全部實體化」這類症狀,就懷疑這條線。14
flowchart TB
accTitle: 安全性產品或搜尋索引器誘發的補水
accDescr: 完整掃描或搜尋索引器碰到預留位置內容時,尊重 RECALL 屬性的產品會略過,不尊重的產品會讓每個檔案補水,造成夜間頻寬壓力或早晨實體化
av["完整掃描或搜尋索引器"] --> care{"尊重 RECALL 屬性嗎?"}
care -->|尊重的產品| skip["略過預留位置"]
care -->|不尊重的產品| hyd["碰到內容並補水"]
hyd --> sym1["夜間頻寬與磁碟被打滿"]
hyd --> sym2["到早上檔案已全部實體化"]
圖 14: 不尊重屬性的掃描會誘發每個檔案補水,並以夜間負載或早晨實體化顯現。
6. 應用開發端的對應 ── 尊重預留位置
作為開發者的基本方針,是把預留位置當成 「有擷取成本的檔案」而不是「壞掉的檔案」。
- 列舉時用屬性判斷,不要輕易開啟。 資料夾掃描時,先從屬性(第 4 章的判斷)確認是否僅限線上,只開啟你需要內容的檔案。對「缺了也不致命」的處理 ── 記錄收集、雜湊計算、預覽產生 ── 給略過預留位置的選項。
// 把 .NET 的 FileAttributes 未定義的值用數字定義
const FileAttributes RecallOnDataAccess = (FileAttributes)0x00400000;
const FileAttributes RecallOnOpen = (FileAttributes)0x00040000;
static bool IsCloudPlaceholder(FileAttributes attributes) =>
(attributes & (RecallOnDataAccess | RecallOnOpen | FileAttributes.Offline)) != 0;
foreach (var file in new DirectoryInfo(watchFolder).EnumerateFiles("*.csv"))
{
if (IsCloudPlaceholder(file.Attributes))
{
log.Warn($"{file.Name} 僅限線上;這次略過");
continue;
}
Import(file.FullName);
}
flowchart TB
accTitle: 列舉時用屬性判斷再開啟的路徑
accDescr: 資料夾掃描時先在列舉確認屬性;若是預留位置就略過並留警告記錄,只對其他檔案執行匯入,以免輕率補水
enum["列舉時確認屬性"] --> ph{"預留位置?"}
ph -->|是| skip["略過並留警告記錄"]
ph -->|否| imp["執行匯入"]
skip -.-> note["只開啟需要內容的檔案的方針"]
圖 15: 列舉時用屬性判斷,略過預留位置而不開啟,以免輕率補水。
- 注意 FILE_FLAG_OPEN_NO_RECALL 不是「不要下載」的保證。 在 CreateFile 指定此旗標,可表示「取得的資料應留在遠端、不要寫回本機儲存」的意圖。不過它只是 不要讓取得的資料常駐本機的旗標;若你讀內容,資料傳輸本身仍會發生。若要避開頻寬與延遲本身,只用屬性、大小、時間戳結束 ── 不要要求讀取存取(以存取權限 0 開啟,或用列舉結果的中繼資料)。那才最安全。9
flowchart TB
accTitle: FILE_FLAG_OPEN_NO_RECALL 的效果與界限
accDescr: FILE_FLAG_OPEN_NO_RECALL 是不讓取得的資料常駐本機的旗標;若讀內容,資料傳輸本身仍會發生,因此若要避開傳輸,最安全是只用屬性等中繼資料結束
flag["以 NO_RECALL 旗標開啟"] --> read["讀取內容"]
read --> transfer["發生資料傳輸"]
transfer --> nolocal["不會常駐本機"]
meta["只用中繼資料結束"] --> safe["不發生傳輸;最安全"]
圖 16: FILE_FLAG_OPEN_NO_RECALL 只避免常駐本機;若要避開傳輸本身,只用中繼資料結束。
- 在錯誤訊息裡寫「這在 OneDrive 底下」。 讀取失敗時,只要確認目標路徑是否在
%OneDrive%底下並寫進訊息,現場與服務台的分診時間就會大幅縮短。若偵測到 0x8007016A 這類雲端檔案系列錯誤,理想是告訴使用者「請檢查 OneDrive 的狀態」。 - 不要把應用的資料夾放在 OneDrive 底下。 在 KFM 環境,「文件」也在 OneDrive 底下。把應用的設定、資料庫、工作檔放在
%ProgramData%或%LocalAppData%,不要把桌面或文件選成預設儲存位置或預設匯入資料夾。決定放哪裡,見「Windows應用程式資料儲存位置怎麼選」。 - 決定使用者選了 OneDrive 底下位置時的行為。 對讓使用者選擇儲存位置的應用,事先在規格裡納入設計決策,例如所選路徑在 OneDrive 底下(
OneDrive/OneDriveCommercial環境變數的路徑底下)時警告,或只拒絕放置鎖定檔或資料庫。
7. IT 端的對應 ── 用釘選與原則控制
從 IT 的位置,務實的營運不是「整段關掉隨選檔案」,而是 只在業務需要的地方保證實體。
- 釘選業務應用會讀的資料夾。 從檔案總管右鍵選單選「一律保留在此裝置上」,或在映像指令碼執行
attrib +p -u <folder> /s /d(同時指定-u,才能把已是僅限線上的檔案可靠切到釘選)。釘選的檔案在本機保證有實體,也不在稍後談到的自動轉成僅限線上的範圍內。72 - 刻意設定 KFM 與隨選檔案,而不是「注意到時已經開著」。 主要原則(群組原則 / Intune)如下。111
| 目的 | 原則(登錄值) | 效果 |
|---|---|---|
| 控制隨選檔案 | Use OneDrive Files On-Demand (FilesOnDemandEnabled) | 開:新使用者預設僅限線上。關:傳統完整同步 |
| 一次套用 KFM | Silently move Windows known folders to OneDrive (KFMSilentOptIn) | 不經使用者操作就搬移桌面等 |
| 禁止 KFM | Prevent users from moving their Windows known folders to OneDrive (KFMBlockOptIn) | 禁止搬移已知資料夾 |
| 禁止關掉 KFM | Prevent users from redirecting their Windows known folders to their PC (KFMBlockOptOut) | 禁止使用者關掉 |
| 降低小組網站容量 | Convert synced team site files to online-only (DehydrateSyncedTeamSites) | 把已同步的小組網站改成僅限線上(注意它朝實體消失的方向作用) |
- 了解儲存感知如何移動。 儲存感知有一項功能,把若干天未開啟的雲端檔案自動退回僅限線上,天數可用原則(ConfigStorageSenseCloudContentDehydrationThreshold)設定。預設是 0(不自動退回),但若使用者從設定畫面開啟,或組織為低容量裝置設定了,則「上週開過的檔案變回雲朵圖示」會當正常行為發生。釘選的檔案不在範圍內,所以「釘選業務資料夾」在這裡也有效。122
flowchart TB
accTitle: 儲存感知自動轉成僅限線上的分支
accDescr: 在儲存感知的自動釋放中,釘選的檔案不在範圍內且實體保留;未釘選且若干天未開啟的檔案會被退回僅限線上
ss["儲存感知自動釋放"] --> pin{"已釘選?"}
pin -->|是| stay["不在範圍內;實體保留"]
pin -->|否| old{"若干天未開啟?"}
old -->|是| dehyd["退回僅限線上"]
old -->|否| keep["實體保留"]
ss -.-> def["預設 0 不自動退回"]
圖 17: 儲存感知把若干天未開啟的檔案退回僅限線上,但釘選不在範圍內。
- 停用隨選檔案前先估計影響。 停用 FilesOnDemandEnabled 會變成傳統完整下載同步,但磁碟消耗與第一次同步的頻寬負載會跳升。Microsoft 建議維持開啟,停用應視為確認「目標使用者資料量小」與「磁碟有餘裕」之後的有限措施。112
- 寫進支援程序。 把下一章的分診程序放進「桌面上的檔案打不開」詢問範本,即使承辦人換了,對應品質也能維持。
8. 分診程序 ── 接到「檔案打不開」時
接下諮詢時,由上往下確認。
| # | 要確認的事 | 方法 | 你會知道的事 |
|---|---|---|---|
| 1 | 路徑在 OneDrive 底下嗎? | 用 echo %OneDrive% 確認同步根並對上目標路徑。也在檔案總管位址列確認「桌面」的實際路徑 |
KFM / OneDrive 是否介入 |
| 2 | 檔案的狀態 | 用 attrib <path> 確認 U(僅限線上)、P(釘選)、O。也看內容的「磁碟上的大小」 |
實體是否在本機,或是預留位置 |
| 3 | OneDrive 是否在執行 | 工作列圖示(已登入、暫停、錯誤)、Get-Process OneDrive |
補水是否可能。0x8007016A 典型是停止或設定錯誤8 |
| 4 | 網路 | 公司 Proxy、頻寬、到 OneDrive 服務的可達性 | 下載本身是否可能 |
| 5 | 磁碟可用空間 | 目標磁碟區的可用空間。容量低時也有 OneDrive 阻擋下載的原則 | 補水失敗的另一因素 |
| 6 | 失敗紀錄 | 記下應用的錯誤碼與發生時間,對上同步應用的錯誤顯示 | 是應用端問題還是 OneDrive 端問題 |
權宜之計是對目標資料夾按右鍵,選「一律保留在此裝置上」(或 attrib +p /s /d)。這樣實體會在本機排齊,業務可以恢復。在此之上,再決定本質原因在應用端(第 6 章)還是 IT 端(第 7 章),作為永久對應。
flowchart TB
accTitle: 從權宜到永久對應的路徑
accDescr: 權宜之計是把目標資料夾設成一律保留在此裝置上,實體在本機排齊後業務可恢復;在此之上決定本質原因在應用端還是 IT 端,再進入永久對應
aid["權宜釘選"] --> restore["實體在本機排齊"]
restore --> resume["業務恢復"]
resume --> judge{"本質原因在哪?"}
judge -->|應用端| dev["到第 6 章的對應"]
judge -->|IT 端| ops["到第 7 章的對應"]
圖 18: 權宜是釘選、排齊實體、恢復業務;永久對應在決定是應用端還是 IT 端之後進行。
若確認到這裡,「路徑不在 OneDrive 底下」且「也不是預留位置」,就往共用資料夾或路徑長度等其他定番原因走。「網路磁碟機與 UNC 路徑的陷阱」與「MAX_PATH 與 Windows 路徑・檔案名稱的陷阱」是接下來的地圖。
9. 總結
- KFM 可能已把真正的桌面、文件、圖片搬到
C:\Users\<名稱>\OneDrive\底下。假設固定路徑的應用會在這裡壞掉。用已知資料夾 API 解析是第一步。 - 隨選檔案預設開啟,沒有本機內容的預留位置理所當然存在。預留位置是 Cloud Files API(cldflt.sys)的重新分析點,開啟就會自動補水。
- 狀態可從檔案屬性(OFFLINE / RECALL_ON_DATA_ACCESS / PINNED / UNPINNED)判斷,在 attrib 顯示為 O、P、U。只檢查屬性不會引發下載。
- 業務應用事故呈現為離線時補水失敗、批次處理的完整下載、沒預期屬性的程式碼、FileSystemWatcher 與同步的交互、獨占鎖定與同步的衝突,以及安全性產品誘發的補水。
- 應用端的基本是「用屬性判斷、不要輕易開啟」、「不要把資料夾放在 OneDrive 底下」、「出錯時說它在 OneDrive 底下」。
- IT 端用「釘選業務資料夾」與「KFM、隨選檔案、儲存感知的原則控制」做出預期狀態。
- 分診可依路徑 → attrib → OneDrive 執行 → 網路 → 可用空間 → 紀錄的順序機械地走完。
下次接到「檔案在那裡但打不開」,先問這個。
那個檔案真的在本機磁碟上嗎?還是只有雲端的外表坐在那裡?
相關文章
- Windows I/O 的深層(第 5 回) ── NTFS 的內部結構:從 MFT 理解檔案系統
- FileSystemWatcher 的使用方法與注意事項 - 漏掉、重複通知、完成判定的陷阱
- 網路磁碟機與 UNC 路徑的陷阱 ── 業務應用程式處理檔案伺服器(共用資料夾)的實務
- 檔案整合的互斥控制基礎 - 檔案鎖與原子性 claim 的最佳實務
- Windows應用程式資料儲存位置怎麼選 ── SQLite / JSON / 登錄檔 / Access 判斷表
- MAX_PATH 與 Windows 路徑・檔案名稱的陷阱 ── 260 字元限制、保留名稱、結尾句點、大小寫
相關諮詢領域
小村軟體有限公司處理與 OneDrive、雲端儲存有關的業務應用故障調查 ── 「以前能用的匯入換電腦後就不能用」、「只有某台電腦打不開檔案」── 假設預留位置的檔案處理與監視處理的設計與修正,以及 KFM / 隨選檔案環境下儲存位置設計的審查。從釐清症狀開始也沒關係 ── 歡迎聯絡。
參考連結
-
Microsoft Learn, Redirect and move Windows known folders to OneDrive. KFM 把桌面、文件、圖片搬到 OneDrive 底下,以及提示、無訊息套用、禁止關閉、禁止搬移等原則。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Recommended sync app configuration. 隨選檔案預設開啟且建議維持開啟,以及儲存感知會清理「未釘選的本機可用檔案」。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Support, Save disk space with OneDrive Files On-Demand for Windows. 隨選檔案的三種狀態,以及「一律保留在此裝置上」與「釋放空間」操作。 ↩ ↩2 ↩3
-
Microsoft Learn, Build a Cloud Sync Engine that Supports Placeholder Files. Cloud Files API 概觀、預留位置只持有約 1KB 中繼資料且開啟會自動補水、重新分析點對同步引擎與 %systemroot% 以外的程序隱藏,以及背景補水的快顯與封鎖。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, File Attribute Constants. FILE_ATTRIBUTE_OFFLINE、RECALL_ON_OPEN、RECALL_ON_DATA_ACCESS、PINNED、UNPINNED 的定義與值。 ↩ ↩2
-
Microsoft Learn, attrib. attrib 指令語法,以及包含 O(離線)、P(釘選)、U(取消釘選)的屬性旗標。 ↩ ↩2
-
Microsoft Learn, Query and set Files On-Demand states in Windows. 用 attrib 確認隨選檔案狀態,以及用 +p、-p、+u 設定,還有 CldFlt 服務。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Error 0x8007016a when copying files in OneDrive. 錯誤 0x8007016A “The cloud file provider is not running” 在 OneDrive 設定錯誤或停止時發生,以及解決步驟。 ↩ ↩2 ↩3
-
Microsoft Learn, CreateFileW function (fileapi.h). FILE_FLAG_OPEN_NO_RECALL 是表示「要求的資料應留在遠端、不要傳回本機儲存」的旗標(不阻止取得資料本身),以及以存取權限 0 開啟來取得屬性。 ↩ ↩2
-
Microsoft Learn, Handling placeholders. 預留位置應設定 FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS,以及對帶此屬性的檔案輕率讀寫會招來不必要的補水或資料損毀。 ↩ ↩2
-
Microsoft Learn, IT Admins - Use OneDrive policies to control sync settings. 用 GPO/Intune 設定 OneDrive 同步應用的原則,包括 FilesOnDemandEnabled、KFMSilentOptIn、KFMBlockOptIn、KFMBlockOptOut、DehydrateSyncedTeamSites。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Policy CSP - Storage. 儲存感知可把若干天未開啟的雲端檔案改成僅限線上、預設 0(不自動退回),以及 0–365 天的設定。 ↩ ↩2 ↩3
-
Microsoft Support, What do the OneDrive icons mean?. 檔案總管顯示的雲朵與勾選等狀態圖示的意義。 ↩
-
Microsoft Learn, Plan for an Azure File Sync deployment. 防毒掃描可能造成帶 RECALL_ON_DATA_ACCESS 屬性的檔案被召回,以及 Microsoft Defender 等產品在隨選掃描時會略過帶此屬性的檔案。 ↩
相關文章
共用相同標籤的最新文章。能以相近的主題延伸理解。
使用 Get-WinEvent 有效率地調查事件記錄 ── 篩選的速度決定調查所需的時間
本文整理如何用 PowerShell 有效率地進行 Windows 事件記錄的調查。說明以 Where-Object 篩選為什麼慢、FilterHashtable 與 XPath 的使用區分、重新開機、登入、應用程式異常結束等調查手法,以及跨多台伺服器收集記錄的方法。
從睡眠恢復就壞掉的應用程式 ── Windows 電源事件的機制,以及耐得住恢復的業務應用寫法
打開筆電,業務應用程式的連線卻斷了──原因是設計從未把睡眠算進去。本文依一次資訊整理 WM_POWERBROADCAST 的通知流程、Modern Standby 的行為、斷線/重連設計、睡眠抑制,以及調查指令。
DllMain 與載入器鎖定 ── 「DLL 初始化什麼都別做」真正的理由
為什麼不能從 DllMain 呼叫 LoadLibrary,也不能和其他執行緒同步。本文依一次資訊說明載入器鎖定如何序列化每個 DLL 通知、結構上必定成立的死結場景、延遲初始化的正確設計,以及無回應的調查方式。
「沒有回應」的真面目 ── Windows 如何判定應用程式當住,以及不卡住的設計
Windows 的「沒有回應」是作業系統判定視窗 5 秒未取出訊息後,換成幽靈視窗的機制。本文涵蓋該判定的內部、無回應的經典原因、把重工作移出 UI 執行緒的設計,以及調查無回應的程序。
虛假喚醒 ── 條件變數為何「沒被通知也會醒來」,以及 Windows 上正確的等待方式
條件變數的等待即使沒有通知到來也可能返回(虛假喚醒)。本文從 Windows 實作說明規格為何允許它,並展示 Win32、C++ 與 C# 裡用 while 迴圈與述語正確等待的寫法。
相關主題
與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。
Windows 技術主題
彙整 KomuraSoft LLC 關於 Windows 開發、故障調查與既有資產活用文章的主題中心。
故障調查 & 長期運行故障
整理間歇性故障、通訊診斷、長期運行當機、失敗路徑測試基礎的主題頁面。
與本主題相關的服務
本文連結到以下服務頁面,歡迎從最接近的入口查看。
Windows 應用程式開發
支援包含常駐處理、設備連動、運作日誌與可維護結構的 Windows 桌面應用程式。
故障調查 & 根本原因分析
調查難以重現的故障、長時間執行後的問題、記憶體洩漏、通訊停滯等棘手的正式環境問題。
常見問題
整理諮詢這個主題時常見的問題。
- 業務應用說「找不到檔案」,讀不了放在桌面上的 CSV。為什麼?
- 多數情況是桌面資料夾本身已被 OneDrive 的已知資料夾搬移(KFM)移到 C:\Users\<使用者名稱>\OneDrive\Desktop,或檔案已變成僅限線上的預留位置。假設固定路徑如 C:\Users\<使用者名稱>\Desktop 的應用,搬移後就找不到檔案。即使路徑正確,OneDrive 停止或網路不穩時,僅限線上的檔案也可能打不開。先確認目標路徑是否在 OneDrive 底下,並用 attrib 指令檢查是否有 U(僅限線上)。權宜之計是在右鍵選單選「一律保留在此裝置上」,把實體留在本機。
- 程式能判斷檔案是否僅限線上嗎?
- 可以。僅限線上的預留位置帶有 FILE_ATTRIBUTE_OFFLINE 與 FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS(0x00400000)等屬性,因此不必下載內容就能從檔案屬性判斷狀態。取得屬性或列舉資料夾不會引發補水(下載)。在 .NET 裡有些值未定義於 FileAttributes,因此要轉成整數再用位元運算檢查。若確實需要開啟但不讀內容,也可用 CreateFile 的 FILE_FLAG_OPEN_NO_RECALL 這類手段。
- 關掉隨選檔案就能解決問題嗎?
- 把關閉當成最後手段。關掉後同步範圍內的每個檔案都會下載到本機,磁碟容量與第一次同步的網路負載都會變大,Microsoft 也建議維持開啟。實務上較有彈性的做法是只把業務應用會讀的資料夾設成「一律保留在此裝置上」(釘選)。更根本、也更可靠的修正,是重新設計,讓應用的資料夾與匯入資料夾不要落在 OneDrive 管理之下。
- 我設了「一律保留在此裝置上」,有些檔案最後還是變回雲朵圖示。為什麼?
- 先用 attrib 指令確認檔案真的有釘選(P 屬性)。已釘選的檔案不在儲存感知自動轉成僅限線上的範圍內,但只因有人開啟而「本機可用」、並未釘選的檔案,可能依儲存感知設定與原則在一段時間後回到僅限線上。使用者自己的「釋放空間」操作,以及把小組網站檔案改成僅限線上的原則(DehydrateSyncedTeamSites),也會讓雲朵圖示回來。業務上必須留在本機的資料夾,請以資料夾範圍釘選來營運。