Поделиться через


Отслеживание изменений файловой системы в фоновом режиме

Основные API

Класс StorageLibraryChangeTracker позволяет приложениям отслеживать изменения в файлах и папках по мере перемещения пользователей по системе. С помощью класса StorageLibraryChangeTracker приложение может отслеживать:

  • Операции с файлами, включая добавление, удаление, изменение.
  • Операции папок, такие как переименование и удаление.
  • Файлы и папки, перемещающиеся на диске.

Используйте это руководство для изучения модели программирования для работы с средством отслеживания изменений, просмотра примера кода и понимания различных типов операций файлов, отслеживаемых StorageLibraryChangeTracker.

StorageLibraryChangeTracker работает для пользовательских библиотек или для любой папки на локальном компьютере. К ним относятся вторичные диски или съемные диски, но не включают диски NAS или сетевые диски.

Использование средства отслеживания изменений

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

Чтобы использовать средство отслеживания изменений в папке, выполните следующие действия.

  1. Включите отслеживание изменений для папки.
  2. Дождитесь изменений.
  3. Прочитайте изменения.
  4. Примите изменения.

В следующих разделах описывается каждый из шагов с некоторыми примерами кода. Полный пример кода представлен в конце статьи.

Включение средства отслеживания изменений

Первое, что нужно сделать приложению, заключается в том, чтобы сообщить системе, что она заинтересована в отслеживании изменений данной библиотеки. Это делается путем вызова метода Enable в средстве отслеживания изменений для интересующей библиотеки.

StorageLibrary videosLib = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Videos);
StorageLibraryChangeTracker videoTracker = videosLib.ChangeTracker;
videoTracker.Enable();

Несколько важных примечаний:

  • Перед созданием объекта StorageLibrary убедитесь, что приложение имеет разрешение на правильную библиотеку в манифесте. Дополнительные сведения см. в разделе разрешения доступа к файлам.
  • Включение является потокобезопасным, не сбрасывает ваш указатель и может вызываться столько раз, сколько вам хочется (подробнее об этом позже).

Включение пустого средства отслеживания изменений

Дождитесь изменений

После инициализации средства отслеживания изменений начнется запись всех операций, происходящих в библиотеке, даже если приложение не запущено. Приложения могут быть активированы в любой момент, когда есть изменение, зарегистрируясь для события StorageLibraryChangedTrigger.

Изменения, добавляемые в средство отслеживания изменений без их чтения приложением

Прочитайте изменения

Затем приложение может проверить на наличие изменений из трекера изменений и получить список изменений с момента последнего раза, когда оно проверяло. В приведенном ниже коде показано, как получить список изменений из средства отслеживания изменений.

StorageLibrary videosLibrary = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Videos);
videosLibrary.ChangeTracker.Enable();
StorageLibraryChangeReader videoChangeReader = videosLibrary.ChangeTracker.GetChangeReader();
IReadOnlyList changeSet = await changeReader.ReadBatchAsync();

Затем приложение отвечает за обработку изменений в собственном интерфейсе или базе данных по мере необходимости.

чтение изменений из средства отслеживания изменений в базу данных приложений

Подсказка

Второй вызов функции включения необходим для защиты от состояния гонки, если пользователь добавляет другую папку в библиотеку, пока ваше приложение обрабатывает изменения. Без дополнительного вызова Enable код завершится ошибкой ecSearchFolderScopeViolation (0x80070490), если пользователь изменяет папки в своей библиотеке.

Примите изменения

После завершения обработки изменений приложение должно сообщить системе никогда не отображать эти изменения снова путем вызова метода AcceptChangesAsync .

await changeReader.AcceptChangesAsync();

Отметка изменений как прочитанные, чтобы они больше не отображались

Теперь приложение получит новые изменения только при чтении средства отслеживания изменений в будущем.

  • Если изменения произошли между вызовом ReadBatchAsync и AcceptChangesAsync, указатель будет перемещен только к последнему обнаруженному изменению приложением. Эти другие изменения по-прежнему будут доступны при следующем вызове ReadBatchAsync.
  • Не принимать изменения приведет к тому, что система возвращает тот же набор изменений при следующем вызове ReadBatchAsync.

Важные вещи, которые нужно запомнить

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

Переполнение буфера

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

В этом случае ReadBatchAsync вернет код ошибки StorageLibraryChangeType.ChangeTrackingLost. Если приложение получает этот код ошибки, это означает несколько вещей:

  • Буфер перезаписал себя с момента последнего просмотра. Лучший план действий заключается в том, чтобы пересканировать библиотеку, потому что любая информация от трекера будет неполной.
  • Средство отслеживания изменений больше не будет возвращать изменения до тех пор, пока вы не вызовете Сброс. После вызова reset приложением указатель будет перемещён к последнему изменению, и отслеживание возобновится нормально.

Такие случаи должны быть редкими, но в сценариях, когда пользователь перемещает по своему диску большое количество файлов, мы не хотим, чтобы средство отслеживания изменений раздувалось и занимало слишком много места. Это должно позволить приложениям реагировать на массовые операции файловой системы, не повреждая взаимодействие с клиентами в Windows.

Изменения в StorageLibrary

Класс StorageLibrary существует как виртуальная группа корневых папок, содержащих другие папки. Чтобы согласовать это со средством отслеживания изменений файловой системы, мы сделали следующие выборы:

  • Все изменения, внесенные в потомки папок корневой библиотеки, будут представлены в средстве отслеживания изменений. Папки корневой библиотеки можно найти с помощью свойства папок .
  • Добавление или удаление корневых папок из storageLibrary (с помощью RequestAddFolderAsync и RequestRemoveFolderAsync) не создаст запись в отслеживании изменений. Эти изменения можно отслеживать с помощью события DefinitionChanged или перечисления корневых папок в библиотеке с помощью свойства "Папки ".
  • Если в библиотеку добавляется папка с содержимым, уже содержащаяся в ней, уведомления об изменении или записи отслеживания изменений не создаются. Любые последующие изменения в потомках этой папки будут создавать уведомления и записи в журнале отслеживания изменений.

Вызов метода Enable

Приложения должны вызывать Enable сразу после того, как начинают отслеживание файловой системы, и перед каждым перечислением изменений. Это гарантирует, что все изменения будут записаны средством отслеживания изменений.

Собирая это вместе

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

private async void EnableChangeTracker()
{
    StorageLibrary videosLib = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Videos);
    StorageLibraryChangeTracker videoTracker = videosLib.ChangeTracker;
    videoTracker.Enable();
}

private async void GetChanges()
{
    StorageLibrary videosLibrary = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Videos);
    videosLibrary.ChangeTracker.Enable();
    StorageLibraryChangeReader videoChangeReader = videosLibrary.ChangeTracker.GetChangeReader();
    IReadOnlyList changeSet = await changeReader.ReadBatchAsync();


    //Below this line is for the blog post. Above the line is for the magazine
    foreach (StorageLibraryChange change in changeSet)
    {
        if (change.ChangeType == StorageLibraryChangeType.ChangeTrackingLost)
        {
            //We are in trouble. Nothing else is going to be valid.
            log("Resetting the change tracker");
            videosLibrary.ChangeTracker.Reset();
            return;
        }
        if (change.IsOfType(StorageItemTypes.Folder))
        {
            await HandleFileChange(change);
        }
        else if (change.IsOfType(StorageItemTypes.File))
        {
            await HandleFolderChange(change);
        }
        else if (change.IsOfType(StorageItemTypes.None))
        {
            if (change.ChangeType == StorageLibraryChangeType.Deleted)
            {
                RemoveItemFromDB(change.Path);
            }
        }
    }
    await changeReader.AcceptChangesAsync();
}