OneDrive «Файлы по запросу» и бизнес-приложения — какие допущения ломают заполнители и как с этим жить

· · OneDrive, Файлы по запросу, KFM, Windows, Бизнес-приложения, Облачное хранилище, Файловая система, Диагностика, Информационные системы

«Бизнес-приложение не читает CSV, который я сохранил на рабочем столе.» «Импорт, который работал, после замены ПК падает с „файл не найден“.» «Проводник файл показывает, а открытие из приложения даёт ошибку.» — За последние годы такие обращения клиентов стали классикой.

Когда разбираешься, причина часто не баг приложения, а «автоматическое резервное копирование Рабочего стола и Документов» OneDrive (Known Folder Move, KFM) и «Файлы по запросу». Настоящий Рабочий стол переехал в C:\Users\<имя>\OneDrive\Desktop, и часть файлов, которые там видны, — «заполнители» без локального содержимого. Пользователи и ИТ продолжают пользоваться ПК, не замечая этой перемены.

Иными словами, неявное допущение бизнес-приложения, что «файл лежит на локальном диске», без чьего-либо решения заменено допущением, что «файл в облаке, а локально есть только видимость». Статья для ИТ малых и средних компаний и разработчиков приложений Windows собирает по первичным источникам Microsoft Learn, как работают заполнители, как судить о состоянии по атрибутам файла, в какие типичные ловушки попадает бизнес-приложение, что могут сделать сторона разработки и сторона ИТ, и процедуру сортировки, когда вам говорят «файл не открывается».

Замена неявного допущения бизнес-приложенияНеявное допущение бизнес-приложения, что файл на локальном диске, без чьего-либо решения заменено допущением, что реальное содержимое в облаке, а локально есть только видимостьПрежнее неявное допущениеРеальное содержимое на локальном дискеЗаменённое допущениеРеальное содержимое в облакеЛокально есть только видимостьЗаполнитель

Рис. 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

Два пути, которыми включается KFMВход с учётной записью при начальной настройке нового ПК предлагает резервное копирование папок по умолчанию, и продолжение как есть его включает; в организации политика KFMSilentOptIn применяет это массово, не спрашивая пользователяНачальная настройка нового ПКВход с учётной записьюРезервное копирование предлагается по умолчаниюПродолжение как есть включаетПолитика организацииKFMSilentOptInПрименено массово без вопросаKFM включён

Рис. 2: KFM включается, никто не замечая, либо предложением по умолчанию при начальной настройке, либо политикой тихой применения организации.

Неловкость в том, что внешний вид в Проводнике почти не меняется. API известных папок оболочки (SHGetKnownFolderPath и Environment.GetFolderPath в .NET) возвращают верный путь после переноса, поэтому воспитанное приложение продолжает работать. Ломается приложение, которое зашивает фиксированный путь вроде C:\Users\%USERNAME%\Desktop в файл настроек или в код. Типичный шаблон импорта, падающего с «файл не найден» после замены ПК, — именно этот.

Как приложение разрешает путь после KFMПосле того как KFM перенёс настоящий Рабочий стол и подобные папки под OneDrive, приложение, использующее API известных папок, продолжает работать с верным путём после переноса, а приложение, зашивающее фиксированный путь, падает с «файл не найден»API известных папокЖёстко зашитый фиксированный путьKFM включёнНастоящий Рабочий стол и подобное уходят под OneDriveКак приложение разрешает путь?Получает верный путь после переноса и продолжает работатьФайл не найден

Рис. 3: После KFM приложение, использующее API известных папок, продолжает работать, а приложение, жёстко зашивающее фиксированный путь, ломается здесь.

2.2. «Файлы по запросу» — видны, но без реального содержимого

Другая нить — «Файлы по запросу». В среде, где они включены, каждый файл на OneDrive виден в Проводнике, но содержимое не скачивается, пока файл не открыт. Эта функция по умолчанию включена в текущем приложении синхронизации, и Microsoft также рекомендует оставлять её включённой.23

Состояние читается по значкам состояния в Проводнике.13

Значок Состояние Локальное содержимое
Облачная метка Только в сети Нет (только заполнитель)
Галочка на белом фоне Доступен локально Есть (но позже может быть освобождено автоматически)
Белая галочка на зелёном фоне Всегда хранить на этом устройстве (закреплено) Есть (вне автоматического освобождения)

Важен здесь средний состояние. Файл, который однажды открыли и у которого теперь есть локальное содержимое, может вернуться в «только в сети» действием пользователя «Освободить место» или Контролем памяти, о котором ниже. Это одна из причин трудно воспроизводимого сбоя вида «в прошлом месяце работало».312

Три состояния «Файлов по запросу» и переходыФайл «только в сети» становится доступным локально при открытии, но «Освободить место» или Контроль памяти могут вернуть его в «только в сети», и только закреплённый файл вне автоматического освобожденияОткрыть (гидратация)Освободить местоКонтроль памятиВсегда хранить на этом устройствеВсегда хранить на этом устройствеСнять закреплениеТолько в сети (облачная метка)Доступен локальноЗакреплён (Всегда хранить на этом устройстве)

Рис. 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

Гидратация при открытии заполнителяКогда приложение открывает заполнитель и читает, минифильтр cldflt.sys обнаруживает запрос, велит поставщику синхронизации передать данные, ждёт конца скачивания, и тогда чтение продолжаетсяПоставщик синхронизацииМинифильтр cldflt.sysБизнес-приложениеПоставщик синхронизацииМинифильтр cldflt.sysБизнес-приложениеЗапрос открытия и чтенияУказать передачу данныхСкачивание завершеноЧтение продолжается

Рис. 5: Чтение заполнителя продолжается после того, как минифильтр заставил поставщика синхронизации получить данные.

Слово «точка повторного разбора» пугает совместимостью с существующим кодом, который «особо обрабатывает точку повторного разбора, если её обнаруживает», но ради совместимости Cloud Files API скрывает факт, что это точка повторного разбора, ото всех, кроме движка синхронизации и процессов под %systemroot%. Обычному приложению это выглядит как «обычный файл, который просто чуть медленнее открывается». Эта тщательная прозрачность удобна и одновременно причина, почему «приложение ломает свои допущения, не замечая».4 Сам механизм точек повторного разбора объяснён в «NTFS Internals».

Сокрытие точки повторного разбора и разница во внешнем видеНастоящая сущность заполнителя — точка повторного разбора, но Cloud Files API скрывает это от процессов кроме движка синхронизации, поэтому обычному приложению это выглядит как обычный файл, который просто чуть медленнее открываетсяДвижок синхронизации и подобноеЛюбое другое приложениеЗаполнитель (точка повторного разбора)Какой процесс открыл?Видно как точка повторного разбораВыглядит как обычный файлВыглядит лишь чуть медленнее открывающимся

Рис. 6: Факт, что это точка повторного разбора, скрыт ото всех, кроме движка синхронизации, и обычному приложению это выглядит как обычный файл.

В свойствах Проводника у заполнителя характерный вид: «Размер» показывает исходный размер, а «Размер на диске» почти 0. Допущение «есть размер, значит должно быть реальное содержимое» здесь не держится.

Как заполнитель выглядит в свойствахВ свойствах Проводника заполнитель показывает исходный размер как Размер, а Размер на диске почти 0, поэтому допущение, что есть размер и значит должно быть реальное содержимое, не держитсяСвойства заполнителяРазмер — исходный размерРазмер на диске почти 0Допущение, что есть реальное содержимоеЛокального содержимого нет

Рис. 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.

Порядок перехода из «только в сети» в «доступен локально»Выполнение одного attrib -p на файле «только в сети» оставляет атрибут U и реальное содержимое не извлекается; нужна процедура сначала скачать реальное содержимое через attrib +p, затем -pтолько attrib -pattrib +pattrib -pТолько в сети (U)Остаётся U; реальное содержимое не извлеченоЗакреплено (скачать реальное содержимое)Доступен локально

Рис. 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(), и получение атрибутов или размера успешны. Получается шаблон ошибки, который интуиция локального диска не объясняет: «проверка существования прошла, а чтение упало».

Ветви при доступе к файлу «только в сети»Проверка существования и получение атрибутов и размера успешны, но чтение содержимого запускает гидратацию; если OneDrive работает и сеть здорова, можно читать после скачивания, иначе падение с ошибкой вроде 0x8007016A или тайм-аутомДаНетПроверка существования или получение атрибутов или размераУспехЧтение содержимогоГидратация начинаетсяOneDrive работает и сеть здорова?Читается после скачиванияОшибка вроде 0x8007016A или тайм-аут

Рис. 9: Проверка существования может пройти, а чтение — упасть. Успех или неудача зависят от того, работает ли OneDrive, и от сети.

5.2. Пакетная обработка провоцирует скачивание каждого файла

Направьте пакет, читающий каждый файл в папке, расчёт хеша, полнотекстовый поиск или самодельную резервную копию на дерево под OneDrive — и провоцируется гидратация каждого файла, которого вы касаетесь. Для папки в несколько ГБ обработка становится ненормально медленной, скачивание также заполняет диск, а на ПК с малой ёмкостью нехватка свободного места приглашает другой сбой. Ёмкость, которую «Файлы по запросу» должны были экономить, исчезает за одно полное сканирование.

Кроме того, если приложение вызывает гидратацию без явного действия пользователя, Windows может показать тост и дать пользователю выбор заблокировать. После блокировки это приложение дальше проваливает скачивания (снять можно в «Автоматические загрузки файлов» в Параметрах). Это одна из причин «импорт падает только на конкретном ПК».4

Как пакет провоцирует скачивание каждого файлаПакет под OneDrive провоцирует гидратацию каждого файла, которого касается, вызывая задержку обработки и давление на диск, и если пользователь блокирует на тосте, скачивания дальше проваливаютсяДаНетПакет под OneDriveГидратировать каждый затронутый файлЗадержка обработки и давление на дискМожет появиться тостПользователь заблокировал?Скачивания дальше проваливаютсяСкачивание продолжается

Рис. 10: Пакет провоцирует гидратацию каждого файла, и если его блокируют на тосте, сбои продолжаются дальше.

5.3. Неверное поведение кода, который не ждёт этих атрибутов

Код, который не знает FILE_ATTRIBUTE_OFFLINE или RECALL_ON_DATA_ACCESS, ведёт себя неверно в неожиданных местах.

  • Атрибуты проверяются на точное равенство (attributes == FileAttributes.Archive и подобное), поэтому заполнитель исключается или обрабатывается как ошибка как «неожиданный файл»
  • Решение об исключении в средстве резервного копирования или синхронизации толкует атрибут OFFLINE как «уже уехало на ленту» и пропускает (или, наоборот, извлекает каждый файл, который должно было исключить)
  • Проверка только для чтения или операция с битом архива ломает комбинацию атрибутов
Шаблоны неверного поведения кода, который не ждёт атрибутовКод, который не знает атрибуты заполнителей, ведёт себя неверно как исключение или обработка ошибки из теста точного равенства, пропуск или полное извлечение из неверного толкования OFFLINE, или ломает комбинацию атрибутовКод, который не ждёт атрибутовТест точного равенстваНеверно толкует OFFLINEОперация с атрибутом ломает комбинациюИсключён или в ошибке как неожиданныйПропуск или полное извлечение

Рис. 11: Код, который не знает OFFLINE или атрибуты семейства RECALL, ведёт себя неверно как исключение, неверный пропуск или разрушение атрибутов.

Руководство Microsoft для разработчиков минифильтров прямо говорит не выдавать неосторожное чтение или запись файлу с RECALL_ON_DATA_ACCESS. Документ нацелен на драйверы ядра, но принцип «трогать содержимое файла с этим атрибутом = возникает стоимость извлечения» применим как есть к приложению в пользовательском режиме.10

5.4. Взаимодействие FileSystemWatcher и синхронизации

Наблюдайте папку под OneDrive через FileSystemWatcher — и получаете не только действия пользователя, но и большое число событий от активности приложения синхронизации. Каждый раз, когда изменение на другом устройстве синхронизируется, и каждый раз, когда гидратация или дегидратация меняет атрибуты или размер, может сработать событие Changed. Далее проект, который пишет результат наблюдения-и-импорта обратно в ту же папку, становится «штормом уведомлений об изменении» в цикле запись → выгрузка → обновление атрибутов → ещё одно событие. Прореживание событий и проектирование проверки реального содержимого разобраны в «Практическое руководство по FileSystemWatcher», но под OneDrive потребность в этом на ступень выше.

Цикл уведомлений об изменении от наблюдения и обратной записиЕсли наблюдающее приложение, получившее событие изменения, пишет результат импорта обратно в ту же папку, выгрузка и обновление атрибутов приложения синхронизации вызывают ещё одно событие, и это становится циклом — штормом уведомленийСобытие измененияНаблюдающее приложение импортируетОбратная запись в ту же папкуПриложение синхронизации выгружаетАтрибуты или размер обновляютсяСинхронизация изменения с другого устройства

Рис. 12: Обратная запись результата импорта в ту же папку становится циклом, в котором активность приложения синхронизации порождает ещё одно событие.

5.5. Конфликты синхронизации при исключительной блокировке и файлы «Копия»

Пока бизнес-приложение держит файл открытым с исключительной блокировкой, приложение синхронизации не может ни выгрузить, ни обновить этот файл. Положить приложение с долго удерживаемой блокировкой (Access .accdb, файл данных в самодельном формате, журнал и подобное) под OneDrive делает ошибки синхронизации нормальным состоянием. Наоборот, когда один и тот же файл правят на нескольких ПК, приложение синхронизации пытается сохранить оба издания и порождает дубликат с именем ПК или конфликтную копию вроде «— копия». Импорт, который предполагает «одна папка, один файл», ведёт себя неверно на этом дубликате. Основы проектирования блокировок — в «Основы взаимного исключения при файловой интеграции».

Проблемы синхронизации из-за исключительной блокировки и правки на нескольких ПКПока приложение держит файл открытым с исключительной блокировкой, приложение синхронизации не может обновить, и ошибки синхронизации становятся нормой; правка одного файла на нескольких ПК порождает конфликтную копию, и допущение одна-папка-один-файл рушитсяПриложение открывает с исключительной блокировкойСинхронизация невозможна; ошибки становятся нормойОдин файл правят на нескольких ПКПорождается конфликтная копияДубликат с именем ПК или копиейДопущение одна-папка-один-файл рушится

Рис. 13: Исключительная блокировка делает ошибки синхронизации нормой, а правка на нескольких ПК приглашает неверное поведение из-за конфликтной копии.

5.6. Антивирус и индексатор поиска провоцируют гидратацию

Содержимое файлов читает не только бизнес-приложение. Полное сканирование антивируса и индексатор поиска тоже провоцируют гидратацию, если касаются содержимого заполнителя. Microsoft Defender и подобные продукты пропускают файлы с атрибутом RECALL_ON_DATA_ACCESS при сканировании по запросу, но это ответ стороны продукта, и нельзя предполагать, что каждый продукт безопасности проявит ту же осторожность. Если видите симптомы вроде «каждую ночь в час сканирования сеть и диск упираются в потолок» или «файлы, которые должны были быть только в сети, к утру все материализовались», подозревайте эту линию.14

Гидратация, спровоцированная продуктом безопасности или индексатором поискаКогда полное сканирование или индексатор поиска касаются содержимого заполнителя, продукт, уважающий атрибут RECALL, пропускает, а продукт, который не уважает, гидратирует каждый файл и вызывает ночное давление на канал или утреннюю материализациюПродукт, который уважаетПродукт, который не уважаетПолное сканирование или индексатор поискаУважает атрибут RECALL?Пропускает заполнительКасается содержимого и гидратируетКанал и диск упираются ночьюК утру файлы все материализовались

Рис. 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);
}
Путь судить по атрибутам при перечислении и затем открыватьПри сканировании папки сначала подтвердите атрибуты при перечислении; если это заполнитель, пропустите и оставьте журнал предупреждения, и выполняйте импорт только на остальных файлах, чтобы избежать неосторожной гидратацииДаНетПодтвердить атрибуты при перечисленииЗаполнитель?Пропустить и оставить журнал предупрежденияВыполнить импортПолитика открывать только файлы, содержимое которых нужно

Рис. 15: Судите по атрибутам при перечислении и пропускайте заполнитель, не открывая его, чтобы избежать неосторожной гидратации.

  • Заметьте, что FILE_FLAG_OPEN_NO_RECALL — не гарантия «не скачивать». Указание этого флага на CreateFile может выразить намерение «полученные данные оставить на удалённой стороне и не записывать обратно в локальное хранилище». Однако это флаг только для того, чтобы не делать полученные данные резидентными локально; если вы читаете содержимое, сама передача данных всё равно происходит. Если хотите избежать полосы и задержки самих по себе, заканчивайте атрибутами, размером и метками времени — не запрашивайте доступ на чтение (открывайте с правами доступа 0, используйте метаданные из результата перечисления). Это самое безопасное.9
Эффект и пределы FILE_FLAG_OPEN_NO_RECALLFILE_FLAG_OPEN_NO_RECALL — флаг, чтобы не делать полученные данные резидентными локально; если вы читаете содержимое, сама передача данных всё равно происходит, поэтому если хотите избежать передачи, самое безопасное — закончить метаданными вроде атрибутовОткрыть с флагом NO_RECALLЧитать содержимоеПроисходит передача данныхНе становится резидентным локальноЗакончить одними метаданнымиПередачи нет; самое безопасное

Рис. 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
Ветви автоматического перевода в «только в сети» у Контроля памятиПри автоматическом освобождении Контроля памяти закреплённый файл вне области и реальное содержимое сохраняется; незакреплённый файл, не открывавшийся несколько дней, возвращается в «только в сети»ДаНетДаНетАвтоматическое освобождение Контроля памятиЗакреплён?Вне области; реальное содержимое сохраняетсяНе открывался несколько дней?Возвращён в только в сетиРеальное содержимое сохраняетсяПо умолчанию 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), как постоянный ответ.

Путь от временной меры к постоянному ответуКак временная мера выставление целевой папки в «Всегда хранить на этом устройстве» выстраивает реальное содержимое локально, чтобы работа могла возобновиться; поверх вы решаете, лежит ли существенная причина на стороне приложения или ИТ, и переходите к постоянному ответуСторона приложенияСторона ИТЗакрепить как временную меруРеальное содержимое выстроено локальноРабота возобновляетсяГде существенная причина?К ответу главы 6К ответу главы 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 работает → сеть → свободное место → запись.

В следующий раз, когда вам скажут «файл есть, но не открывается», сначала спросите это.

Этот файл действительно на локальном диске? Или там сидит только видимость облака?

Похожие статьи

Смежные области консультирования

KomuraSoft LLC занимается расследованием сбоев бизнес-приложений, связанных с OneDrive и облачным хранилищем — «импорт, который работал, после замены ПК больше не работает», «файл не открывается только на конкретном ПК» — проектированием и исправлением обработки файлов и наблюдения, предполагающих заполнители, и ревью проектирования места сохранения в среде KFM / «Файлов по запросу». Начать с изоляции симптома нормально — не стесняйтесь обращаться.

Справочные ссылки

  1. Microsoft Learn, Redirect and move Windows known folders to OneDrive. Что KFM переносит Рабочий стол, Документы и Изображения под OneDrive, и политики предложения, тихого применения, запрета выключения и запрета переноса.  2 3 4

  2. Microsoft Learn, Recommended sync app configuration. Что «Файлы по запросу» по умолчанию включены и оставлять включёнными рекомендуется, и что Контроль памяти очищает «локально доступные файлы, которые не закреплены».  2 3 4 5

  3. Microsoft Support, Save disk space with OneDrive Files On-Demand for Windows. Три состояния «Файлов по запросу» и действия «Всегда хранить на этом устройстве» и «Освободить место».  2 3

  4. Microsoft Learn, Build a Cloud Sync Engine that Supports Placeholder Files. Обзор Cloud Files API, что заполнитель держит лишь около 1 КБ метаданных и открытие автоматически гидратирует, что точка повторного разбора скрыта от процессов кроме движка синхронизации и тех, что под %systemroot%, и тост и блокировка фоновой гидратации.  2 3 4 5 6

  5. Microsoft Learn, File Attribute Constants. Определения и значения FILE_ATTRIBUTE_OFFLINE, RECALL_ON_OPEN, RECALL_ON_DATA_ACCESS, PINNED и UNPINNED.  2

  6. Microsoft Learn, attrib. Синтаксис команды attrib и флаги атрибутов, включая O (офлайн), P (закреплено) и U (откреплено).  2

  7. Microsoft Learn, Query and set Files On-Demand states in Windows. Подтверждение состояния «Файлов по запросу» через attrib и задание через +p, -p и +u, и служба CldFlt.  2 3 4 5

  8. Microsoft Learn, Error 0x8007016a when copying files in OneDrive. Что ошибка 0x8007016A “The cloud file provider is not running” возникает, когда OneDrive неверно настроен или остановлен, и шаги устранения.  2 3

  9. Microsoft Learn, CreateFileW function (fileapi.h). Что FILE_FLAG_OPEN_NO_RECALL — флаг, указывающий, что «запрошенные данные должны остаться на удалённой стороне и не передаваться обратно в локальное хранилище» (он не мешает получить сами данные), и получение атрибутов открытием с правами доступа 0.  2

  10. Microsoft Learn, Handling placeholders. Что у заполнителя должен быть установлен FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS, и что неосторожное чтение или запись файла с этим атрибутом приглашает ненужную гидратацию или порчу данных.  2

  11. Microsoft Learn, IT Admins - Use OneDrive policies to control sync settings. Политики настройки приложения синхронизации OneDrive через GPO/Intune, включая FilesOnDemandEnabled, KFMSilentOptIn, KFMBlockOptIn, KFMBlockOptOut и DehydrateSyncedTeamSites.  2 3 4

  12. Microsoft Learn, Policy CSP - Storage. Что Контроль памяти может сделать облачные файлы, не открывавшиеся несколько дней, только в сети, значение по умолчанию 0 (не возвращать автоматически) и настройка 0–365 дней.  2 3

  13. Microsoft Support, What do the OneDrive icons mean?. Смысл значков состояния в Проводнике, таких как облако и галочки. 

  14. Microsoft Learn, Plan for an Azure File Sync deployment. Что антивирусное сканирование может вызвать отзыв файла с атрибутом RECALL_ON_DATA_ACCESS, и что Microsoft Defender и подобные продукты пропускают файлы с этим атрибутом при сканировании по запросу. 

Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.

Приложения, которые ломаются после выхода из сна — как работают события питания Windows и как строить бизнес-приложения, которые это переживают

Открыли ноутбук — и соединения бизнес-приложения мертвы: причина в проекте, который не учитывал сон. Статья разбирает поток уведомлений W...

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Статья напрямую связана со следующими услугами.

Частые вопросы

Вопросы, которые часто возникают при консультациях по теме статьи.

Бизнес-приложение говорит «файл не найден» и не читает 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, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.

Публичные ссылки

Вернуться в блог