OneDrive «Файлы по запросу» и бизнес-приложения — какие допущения ломают заполнители и как с этим жить
· Го Комура · OneDrive, Файлы по запросу, KFM, Windows, Бизнес-приложения, Облачное хранилище, Файловая система, Диагностика, Информационные системы
«Бизнес-приложение не читает CSV, который я сохранил на рабочем столе.» «Импорт, который работал, после замены ПК падает с „файл не найден“.» «Проводник файл показывает, а открытие из приложения даёт ошибку.» — За последние годы такие обращения клиентов стали классикой.
Когда разбираешься, причина часто не баг приложения, а «автоматическое резервное копирование Рабочего стола и Документов» OneDrive (Known Folder Move, KFM) и «Файлы по запросу». Настоящий Рабочий стол переехал в C:\Users\<имя>\OneDrive\Desktop, и часть файлов, которые там видны, — «заполнители» без локального содержимого. Пользователи и ИТ продолжают пользоваться ПК, не замечая этой перемены.
Иными словами, неявное допущение бизнес-приложения, что «файл лежит на локальном диске», без чьего-либо решения заменено допущением, что «файл в облаке, а локально есть только видимость». Статья для ИТ малых и средних компаний и разработчиков приложений Windows собирает по первичным источникам Microsoft Learn, как работают заполнители, как судить о состоянии по атрибутам файла, в какие типичные ловушки попадает бизнес-приложение, что могут сделать сторона разработки и сторона ИТ, и процедуру сортировки, когда вам говорят «файл не открывается».
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
- Ответ стороны ИТ — «вести закреплениями» и «управлять политикой». Гарантируйте реальное содержимое рабочих папок пунктом «Всегда хранить на этом устройстве» и настраивайте KFM и «Файлы по запросу» намеренно через групповую политику / Intune. Не забывайте, что Контроль памяти тоже может «вернуть неиспользуемые файлы в только в сети».1112
Одним предложением: «файл, видимый в Проводнике» и «файл с реальным содержимым на локальном диске» больше не одно и то же.
2. Что происходит — KFM и «Файлы по запросу»
2.1. Рабочий стол может быть уже не C:\Users\<имя>\Desktop
У приложения синхронизации OneDrive есть функция Known Folder Move (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 и Environment.GetFolderPath в .NET) возвращают верный путь после переноса, поэтому воспитанное приложение продолжает работать. Ломается приложение, которое зашивает фиксированный путь вроде 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, Cloud Files API. Рабочая единица на стороне файловой системы — файловый минифильтр cldflt.sys (имя службы CldFlt, «Windows Cloud Files Filter Driver»), и OneDrive — один из «поставщиков синхронизации», использующих этот API.47
Заполнитель технически — точка повторного разбора (reparse point). В файловой системе есть только метаданные вроде имени, размера и меток времени (около 1 КБ); данных содержимого нет. Когда приложение открывает файл и читает, минифильтр обнаруживает запрос, велит поставщику синхронизации передать данные, ждёт конца скачивания, и тогда чтение продолжается. Это извлечение называют гидратацией; выбросить локальное содержимое и вернуться к заполнителю — дегидратацией.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 Internals».
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] нужно потому, что перечисление FileAttributes в .NET не определяет имён вроде 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 — и провоцируется гидратация каждого файла, которого вы касаетесь. Для папки в несколько ГБ обработка становится ненормально медленной, скачивание также заполняет диск, а на ПК с малой ёмкостью нехватка свободного места приглашает другой сбой. Ёмкость, которую «Файлы по запросу» должны были экономить, исчезает за одно полное сканирование.
Кроме того, если приложение вызывает гидратацию без явного действия пользователя, 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 и синхронизации
Наблюдайте папку под OneDrive через FileSystemWatcher — и получаете не только действия пользователя, но и большое число событий от активности приложения синхронизации. Каждый раз, когда изменение на другом устройстве синхронизируется, и каждый раз, когда гидратация или дегидратация меняет атрибуты или размер, может сработать событие 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), только ли он в сети, и открывайте только файлы, содержимое которых нужно. Обработке, которая «не смертельна, если отсутствует» — сбор журналов, расчёт хеша, генерация предпросмотра — дайте возможность пропускать заполнители.
// Определить числами значения, которые FileAttributes в .NET не определяет
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. Ответ стороны ИТ — управлять закреплениями и политикой
С позиции ИТ реалистичная эксплуатация — не «выключить „Файлы по запросу“ целиком», а гарантировать реальное содержимое только там, где бизнесу оно нужно.
- Закрепляйте папки, которые читает бизнес-приложение. Выберите «Всегда хранить на этом устройстве» в контекстном меню Проводника или выполните
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 | Состояние файла | Подтвердите U (только в сети), P (закреплено) и O через attrib <path>. Также смотрите «Размер на диске» в свойствах |
Реальное содержимое локально или это заполнитель |
| 3 | Работает ли OneDrive | Значок панели задач (вход выполнен, пауза, ошибка), Get-Process OneDrive |
Возможна ли гидратация. 0x8007016A типично остановлен или неверно настроен8 |
| 4 | Сеть | Корпоративный прокси, полоса, достижимость службы OneDrive | Возможно ли само скачивание |
| 5 | Свободное место на диске | Свободное место на целевом томе. При низкой ёмкости есть и политика, по которой OneDrive блокирует скачивания | Ещё один фактор сбоя гидратации |
| 6 | Запись о сбое | Запишите код ошибки приложения и время и сопоставьте с отображением ошибок приложения синхронизации | Проблема на стороне приложения или на стороне OneDrive |
Временная мера — щёлкнуть правой кнопкой целевую папку и выбрать «Всегда хранить на этом устройстве» (или attrib +p /s /d). Это выстраивает реальное содержимое локально, и работа может возобновиться. Поверх решите, лежит ли существенная причина на стороне приложения (глава 6) или на стороне ИТ (глава 7), как постоянный ответ.
flowchart TB
accTitle: Путь от временной меры к постоянному ответу
accDescr: Как временная мера выставление целевой папки в «Всегда хранить на этом устройстве» выстраивает реальное содержимое локально, чтобы работа могла возобновиться; поверх вы решаете, лежит ли существенная причина на стороне приложения или ИТ, и переходите к постоянному ответу
aid["Закрепить как временную меру"] --> restore["Реальное содержимое выстроено локально"]
restore --> resume["Работа возобновляется"]
resume --> judge{"Где существенная причина?"}
judge -->|Сторона приложения| dev["К ответу главы 6"]
judge -->|Сторона ИТ| ops["К ответу главы 7"]
Рис. 18: Временная мера — закрепить, выстроить реальное содержимое и возобновить работу; постоянный ответ идёт после решения, сторона приложения это или сторона ИТ.
Если вы подтвердили досюда и «путь не под OneDrive», и «это тоже не заполнитель», идёте к другим классическим причинам вроде общей папки или длины пути. «Подводные камни сетевых дисков и UNC-путей» и «MAX_PATH и подводные камни путей/имён файлов в Windows» — карта того, что дальше.
9. Итог
- KFM мог перенести настоящие Рабочий стол, Документы и Изображения под
C:\Users\<имя>\OneDrive\. Приложение, которое предполагает фиксированный путь, ломается здесь. Разрешение через API известных папок — первый шаг. - «Файлы по запросу» по умолчанию включены, и заполнители без локального содержимого существуют как само собой разумеющееся. Заполнитель — точка повторного разбора Cloud Files API (cldflt.sys), и открытие автоматически гидратирует.
- Состояние можно судить по атрибутам файла (OFFLINE / RECALL_ON_DATA_ACCESS / PINNED / UNPINNED) и оно выглядит как O, P и U в attrib. Проверка одних атрибутов не вызывает скачивания.
- Аварии бизнес-приложений проявляются как сбой гидратации офлайн, полное скачивание от пакета, код, который не ждёт атрибутов, взаимодействие FileSystemWatcher и синхронизации, конфликт исключительной блокировки и синхронизации, и гидратация, спровоцированная продуктом безопасности.
- На стороне приложения основы — «судить по атрибутам и не открывать зря», «не класть папку данных под OneDrive» и «говорить, что это под OneDrive, когда сообщаете об ошибке».
- На стороне ИТ вы создаёте задуманное состояние «закреплением рабочих папок» и «управлением политикой KFM, „Файлов по запросу“ и Контроля памяти».
- Сортировку можно пройти механически в порядке путь → attrib → OneDrive работает → сеть → свободное место → запись.
В следующий раз, когда вам скажут «файл есть, но не открывается», сначала спросите это.
Этот файл действительно на локальном диске? Или там сидит только видимость облака?
Похожие статьи
- The Depths of Windows I/O (Part 5) — NTFS Internals: Understanding the File System Through the MFT
- Практическое руководство по FileSystemWatcher — защита от потерянных и повторяющихся уведомлений
- Подводные камни сетевых дисков и UNC-путей ── как бизнес-приложения работают с файловым сервером (общей папкой)
- Основы взаимного исключения при файловой интеграции — лучшие практики файловых блокировок и атомарного claim
- Как выбрать место хранения данных Windows-приложения — таблица решений для SQLite / JSON / реестра / Access
- MAX_PATH и подводные камни путей/имён файлов в Windows — лимит 260 символов, зарезервированные имена, конечная точка, регистр
Смежные области консультирования
KomuraSoft LLC занимается расследованием сбоев бизнес-приложений, связанных с OneDrive и облачным хранилищем — «импорт, который работал, после замены ПК больше не работает», «файл не открывается только на конкретном ПК» — проектированием и исправлением обработки файлов и наблюдения, предполагающих заполнители, и ревью проектирования места сохранения в среде KFM / «Файлов по запросу». Начать с изоляции симптома нормально — не стесняйтесь обращаться.
- Разработка приложений для Windows
- Расследование ошибок и причин
- Технические консультации и ревью дизайна
- Связаться с нами
Справочные ссылки
-
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, что заполнитель держит лишь около 1 КБ метаданных и открытие автоматически гидратирует, что точка повторного разбора скрыта от процессов кроме движка синхронизации и тех, что под %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. Политики настройки приложения синхронизации OneDrive через GPO/Intune, включая 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 и подобные продукты пропускают файлы с этим атрибутом при сканировании по запросу. ↩
Похожие статьи
Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.
Приложения, которые ломаются после выхода из сна — как работают события питания Windows и как строить бизнес-приложения, которые это переживают
Открыли ноутбук — и соединения бизнес-приложения мертвы: причина в проекте, который не учитывал сон. Статья разбирает поток уведомлений W...
Введение в доступность приложений Windows — подготовка к UI Automation и требованиям разумного приспособления
На фоне поправки к Закону об устранении дискриминации в отношении лиц с инвалидностью, вступившей в силу в апреле 2024 года, статья с пра...
Ловушки японских шрифтов и символов — как обращаться с JIS2004, IVS и гайдзи в бизнес-приложениях
«Символ 葛 выглядит по-разному на экране и на печатной форме.» «Символ в имени человека не отображается.» Проблемы символов в бизнес-систе...
От Group Policy к Intune — руководство по миграции управления устройствами для малого и среднего бизнеса
Когда сервер AD подходит к замене, остаться с Group Policy или перейти на Entra ID плюс Intune? Статья для малого и среднего бизнеса разб...
Захват пакетов в Windows на практике — как выбрать между pktmon, netsh trace и Wireshark
Сбой связи, в журнале приложения от которого остаётся только «timeout», расследуют на слой ниже — по пакетам, которые реально прошли по п...
Связанные темы
Эти страницы показывают тему статьи в более широком контексте услуг и решений.
Технические темы Windows
Раздел о разработке Windows, расследовании сбоев и использовании существующих активов.
Услуги по этой теме
Статья напрямую связана со следующими услугами.
Разработка приложений для Windows
Бизнес-приложения, интеграция оборудования и средства связи — от требований до разработки.
Частые вопросы
Вопросы, которые часто возникают при консультациях по теме статьи.
- Бизнес-приложение говорит «файл не найден» и не читает CSV, который я положил на рабочий стол. Почему?
- Во многих случаях сама папка рабочего стола перенесена в C:\Users\<имя пользователя>\OneDrive\Desktop функцией Known Folder Move (KFM) OneDrive, либо файл стал заполнителем «только в сети». Приложение, которое предполагает фиксированный путь вроде C:\Users\<имя пользователя>\Desktop, не находит файл после переноса. Даже при верном пути файл «только в сети» может не открыться, когда OneDrive остановлен или сеть нездорова. Сначала проверьте, лежит ли целевой путь под OneDrive, и командой attrib — стоит ли U (только в сети). Как временная мера можно закрепить реальное содержимое локально пунктом «Всегда хранить на этом устройстве» в контекстном меню.
- Может ли программа понять, что файл только в сети?
- Да. Заполнитель «только в сети» несёт атрибуты вроде FILE_ATTRIBUTE_OFFLINE и FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS (0x00400000), поэтому состояние можно судить по атрибутам файла, не скачивая содержимое. Получение атрибутов или перечисление папки не вызывает гидратацию (скачивание). В .NET некоторые значения не определены в FileAttributes, поэтому приводят к целому и проверяют побитовыми операциями. Если нужно открыть, не читая содержимое, доступно и средство вроде FILE_FLAG_OPEN_NO_RECALL у CreateFile.
- Отключение «Файлов по запросу» решает проблему?
- Считайте отключение крайней мерой. Выключение скачивает локально каждый файл в области синхронизации, поэтому ёмкость диска и сетевая нагрузка первой синхронизации становятся большими; Microsoft также рекомендует оставлять функцию включённой. На практике гибче выставить «Всегда хранить на этом устройстве» (закрепить) только для папок, которые читает бизнес-приложение. Более фундаментально надёжное исправление — перепроектировать так, чтобы папка данных и папка импорта приложения не были под управлением OneDrive.
- Я выставил «Всегда хранить на этом устройстве», но некоторые файлы со временем снова становятся облачной иконкой. Почему?
- Сначала командой attrib убедитесь, что у файла действительно есть закрепление (атрибут P). Закреплённый файл вне автоматического перевода в «только в сети» у Контроля памяти, но файл, который лишь «доступен локально», потому что его кто-то открыл, без закрепления, может вернуться в «только в сети» через срок в зависимости от настроек и политики Контроля памяти. Собственное действие пользователя «Освободить место» и политика, делающая файлы сайтов групп только сетевыми (DehydrateSyncedTeamSites), тоже возвращают облачную иконку. Папки, которые для бизнеса должны оставаться локальными, ведите, закрепляя на уровне папки.
Об авторе
Страница с профилем автора статьи.
Го Комура
Представитель KomuraSoft LLC
Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.