Tenere traccia delle modifiche al file system in background

API importanti

La classe StorageLibraryChangeTracker consente alle app di tenere traccia delle modifiche nei file e nelle cartelle mentre gli utenti li spostano all'interno del sistema. Usando la classe StorageLibraryChangeTracker, un'app può monitorare:

  • Operazioni sui file tra cui aggiunta, eliminazione e modifica.
  • Operazioni sulle cartelle, ad esempio ridenominazioni ed eliminazioni.
  • Spostamento di file e cartelle nell'unità.

Usare questa guida per informazioni sul modello di programmazione da usare con il tracciatore di modifiche, visualizzare alcuni esempi di codice e comprendere i diversi tipi di operazioni sui file che vengono rilevati da StorageLibraryChangeTracker.

StorageLibraryChangeTracker funziona per le librerie utente o per qualsiasi cartella nel computer locale. Sono incluse le unità secondarie o unità rimovibili, ma non le unità NAS o le unità di rete.

Uso del rilevatore di modifiche

Il rilevatore di modifiche viene implementato nel sistema come un buffer circolare che archivia le ultime N operazioni di file system. Le app sono in grado di leggere le modifiche al di fuori del buffer e quindi elaborarle nelle proprie esperienze. Una volta che l'app è stata completata con le modifiche, la stessa contrassegna le modifiche man mano che vengono elaborate e queste non vengono più visualizzate.

Per usare il tracciatore delle modifiche in una cartella, seguire questa procedura:

  1. Abilitare il tracciatore delle modifiche per la cartella.
  2. Attendere le modifiche.
  3. Leggere le modifiche.
  4. Accettare le modifiche.

Le sezioni seguenti illustrano ogni passaggio con alcuni esempi di codice. L'esempio di codice completo è disponibile alla fine dell'articolo.

Abilitare il tracciatore di modifiche

La prima cosa che l'app deve fare è indicare al sistema che è interessata a rilevare le modifiche di una determinata libreria. Esegue questa operazione chiamando il metodo Attiva sul tracciatore di modifiche per la libreria di interesse.

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

Alcune note importanti:

  • Assicurarsi che l'app disponga di autorizzazioni per la libreria corretta nel manifesto prima di creare l'oggetto StorageLibrary. Per altre informazioni, vedere Autorizzazioni di accesso ai file.
  • Attiva è thread-safe, non reimposta il puntatore del mouse e può essere chiamato tutte le volte che si desidera (più avanti in questo articolo).

Enabling an empty change tracker

Attendere le modifiche

Dopo aver inizializzato il tracciatore di modifiche, inizierà a registrare tutte le operazioni che si verificano all'interno di una libreria, anche quando l'app non è in esecuzione. Le app possono registrarsi per essere attivate in qualsiasi momento in cui si verifica una modifica effettuando la registrazione per l'evento StorageLibraryChangedTrigger.

Changes being added to the change tracker without the app reading them

Leggere le modifiche

L'app può quindi eseguire il polling delle modifiche dal tracciatore di modifiche e ricevere un elenco delle modifiche dall'ultima volta che ha effettuato il controllo. Il codice seguente illustra come ottenere un elenco delle modifiche dal tracciatore di modifiche.

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

L'app è quindi responsabile dell'elaborazione delle modifiche nell'esperienza o nel database in base alle esigenze.

Reading the changes from the change tracker into an app database

Suggerimento

La seconda chiamata da attivare è per evitare una race condition se l'utente aggiunge un'altra cartella alla libreria mentre l'app sta leggendo le modifiche. Senza la chiamata extra ad Attiva il codice avrà esito negativo con ecSearchFolderScopeViolation (0x80070490) se l'utente sta cambiando le cartelle nella libreria

Leggere le modifiche

Dopo che l'app ha terminato di eseguire le modifiche, deve segnalare al sistema di non visualizzare mai più queste modifiche chiamando il metodo AcceptChangesAsync.

await changeReader.AcceptChangesAsync();

Marking changes as read so they will never be shown again

L'app ora riceverà solo nuove modifiche durante la lettura del tracciatore di modifiche in futuro.

  • Se le modifiche si sono verificate tra la chiamata ReadBatchAsync e AcceptChangesAsync, il puntatore verrà solo spostato in avanti sulla modifica più recente visualizzata dall'app. Le altre modifiche saranno ancora disponibili alla successiva chiamata di ReadBatchAsync.
  • La mancata accettazione delle modifiche porterà il sistema a restituire lo stesso set di modifiche alla successiva chiamata da parte dell'app di ReadBatchAsync.

Informazioni importanti da ricordare

Quando si usa il tracciatore di modifiche, ci sono alcuni aspetti da tenere in considerazione per assicurarsi che tutto funzioni correttamente.

Sovraccarichi del buffer

Anche se si tenta di riservare dello spazio nel tracciatore di modifiche per contenere tutte le operazioni che si verificano nel sistemo fino a quando l'app è in grado di leggerle, è molto facile immaginare uno scenario in cui l'app non legge le modifiche prima che il buffer circolare sovrascriva se stesso. In particolare se l'utente sta ripristinando i dati da un backup o sincronizzando una vasta raccolta di immagini dalla fotocamera del telefono.

In questo caso ReadBatchAsync restituirà il codice di errore StorageLibraryChangeType.ChangeTrackingLost. Se l'app riceve questo codice di errore, può significare un paio di cose:

  • Il buffer si è sovrascritto dall'ultima volta che è stato controllato. La migliore linea di azione è rieseguire la libreria, perché le informazioni fornite dal tracciatore saranno incomplete.
  • Il tracciatore di modifiche non restituirà nessun'altra modifiche finché non si chiama Reimposta. Dopo che l'app chiama Reimposta, il puntatore verrà spostato sulla modifica più recente e il tracciatore riprenderà a funzionare normalmente.

Dovrebbe essere raro ottenere questi casi, ma negli scenari in cui l'utente sta spostando un numero elevato di file sul relativo disco non vogliamo che il tracciatore di modifiche per aumenti notevolmente e occupi troppo spazio di archiviazione. Ciò dovrebbe consentire alle app di reagire alle operazioni di file system di grandi dimensioni senza danneggiare l'esperienza dei clienti in Windows.

Modifiche apportate a un StorageLibrary

La classe StorageLibrary esiste come un gruppo virtuale delle cartelle radice che contiene altre cartelle. Per riconciliarla con un tracciatore di modifiche del file system, abbiamo fatto le scelte seguenti:

  • Qualsiasi modifica ai discendenti delle cartelle della libreria radice verrà rappresentata nel tracciatore di modifiche. Le cartelle della libreria radice possono essere trovate usando la proprietà Cartelle.
  • L'aggiunta o la rimozione di cartelle radice da un StorageLibrary (tramite RequestAddFolderAsync e RequestRemoveFolderAsync) non crea una voce nel tracciatore di modifiche. È possibile tenere traccia di queste modifiche tramite l'evento DefinitionChanged o enumerando le cartelle radice nella libreria usando la proprietà Cartelle.
  • Se alla libreria viene aggiunta una cartella con il contenuto già al suo interno, non verranno generate notifiche della modifica o voci del tracciatore di modifiche. Eventuali modifiche successive ai discendenti di tale cartella genereranno notifiche e voci del tracciatore di modifiche.

Chiamata del metodo Attiva

Le app devono chiamare Abilita appena iniziano a tracciare il file system e prima di ogni enumerazione delle modifiche. Ciò garantisce che tutte le modifiche verranno acquisite dal tracciatore di modifiche.

Riepilogo

Ecco tutto il codice che viene usato per registrare le modifiche dal catalogo video e iniziare a integrare le modifiche dal tracciatore di modifiche.

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();
}