快速存取 UWP 中的檔案屬性Fast access to file properties in UWP 

了解如何從程式庫快速收集檔案和其屬性的清單,並在應用程式中使用那些屬性。Learn how to quickly gather a list of files and their properties from a library and use those properties in an app.  

必要條件Prerequisites 

  • 適用於通用 Windows 平台 (UWP) 應用程式的非同步程式設計   您可以參閱在 C# 或 Visual Basic 中呼叫非同步 API (部分機器翻譯),以了解如何在 C# 或 Visual Basic 中撰寫非同步應用程式。Asynchronous programming for Universal Windows Platform (UWP) apps   You can learn how to write asynchronous apps in C# or Visual Basic, see Call asynchronous APIs in C# or Visual Basic. 若要了解如何使用 C++ 撰寫非同步的 App,請參閱 C++ 的非同步程式設計To learn how to write asynchronous apps in C++, see Asynchronous programming in C++. 
  • 針對程式庫的存取權限   這些範例中的程式碼需要 picturesLibrary 功能,但是您的檔案位置可能需要其他功能,或不需要任何功能。Access permissions to Libraries   The code in these examples requires the picturesLibrary capability, but your file location may require a different capability, or no capability at all. 若要深入了解,請參閱檔案存取權限To learn more, see File access permissions. 
  • 簡易檔案列舉    此範例使用 QueryOptions (英文) 來設定幾個進階列舉屬性。Simple file enumeration    This example uses QueryOptions to set a few advanced enumeration properties. 若要深入了解僅取得小型目錄的簡易檔案清單,請參閱列舉和查詢檔案和資料夾 (部分機器翻譯)。To learn more about just getting a simple list of files for a smaller directory, see Enumerate and query files and folders. 

使用方式Usage  

有許多應用程式都需要列出一組檔案的屬性,但不一定需要與那些檔案直接互動。Many apps need to list the properties of a group of files, but don't always need to interact with the files directly. 例如,某個音樂應用程式一次會播放 (開啟) 一個檔案,但它需要資料夾中所有檔案的屬性,好讓應用程式可以顯示歌曲佇列,或讓使用者可以選擇有效檔案來播放。For example, a music app plays (opens) one file at a time, but it needs the properties of all of the files in a folder so the app can show the song queue, or so the user can choose a valid file to play.

此頁面上的範例不應用於會修改每個檔案的中繼資料,或是會與所有產生的 StorageFiles 進行讀取屬性以外之互動行為的應用程式。The examples on this page shouldn't be used in apps that will modify the metadata of every file or apps that interact with all the resulting StorageFiles beyond reading their properties. 如需詳細資訊,請參閱列舉和查詢檔案和資料夾 (部分機器翻譯)。See Enumerate and query files and folders for more information. 

列舉某個位置中的所有圖片Enumerate all the pictures in a location 

在此範例中,我們將In this example, we will

  • 建置 QueryOptions (英文) 物件來指定應用程式想要盡快列舉檔案。Build a QueryOptions object to specify that the app wants to enumerate the files as quickly as possible.
  • 透過將 StorageFile 物件分頁至應用程式來擷取檔案屬性。Fetch file properties by paging StorageFile objects into the app. 對檔案進行分頁可以降低應用程式所使用的記憶體,並改善其使用者所體驗到的回應性。Paging the files in reduces the memory used by the app and improves its perceived responsiveness.

建立查詢Creating the query 

若要建置查詢,我們會使用 QueryOptions 物件來指定應用程式有興趣只列舉特定類型的影像檔案,並篩選掉受到 Windows 資訊保護 (System.Security.EncryptionOwners) 所保護的檔案。To build the query, we use a QueryOptions object to specify that the app is interested in enumerating only certain types of images files and to filter out files protected with Windows Information Protection (System.Security.EncryptionOwners). 

請務必使用 QueryOptions.SetPropertyPrefetch(英文) 來設定應用程式將會存取的屬性。It is important to set the properties the app is going to access using QueryOptions.SetPropertyPrefetch. 如果應用程式存取未預先擷取的屬性,將會產生顯著的效能負面影響。If the app accesses a property that isn’t prefetched, it will incur a significant performance penalty.

設定 IndexerOption.OnlyUseIndexerAndOptimzeForIndexedProperties (英文) 會告知系統盡快傳回結果,但僅包含在 SetPropertyPrefetch (英文) 中所指定的屬性。Setting IndexerOption.OnlyUseIndexerAndOptimzeForIndexedProperties tells the system to return results as quickly as possible, but to only include the properties specified in SetPropertyPrefetch.

在結果中進行分頁Paging in the results 

使用者的圖片媒體櫃中可能會有上百萬個檔案,因此呼叫 GetFilesAsync (英文) 將會使其電腦無法負擔,因為它會為每個影像建立 StorageFile。Users may have thousands or millions of files in their pictures library, so calling GetFilesAsync would overwhelm their machine because it creates a StorageFile for each image. 解決方法是一次建立固定數量的 StorageFiles,將它們處理至 UI,然後釋放記憶體。This can be solved by creating a fixed number of StorageFiles at one time, processing them into the UI, and then releasing the memory. 

在我們的範例中,我們的做法是使用 StorageFileQueryResult.GetFilesAsync(UInt32 StartIndex, UInt32 maxNumberOfItems) (英文) 來一次僅擷取 100 個檔案。In our example, we do this by using StorageFileQueryResult.GetFilesAsync(UInt32 StartIndex, UInt32 maxNumberOfItems) to only fetch 100 files at a time. 應用程式接著會處理檔案,並允許作業系統隨後釋放記憶體。The app will then process the files and allow the OS to release that memory afterwards. 此技巧會限制應用程式的記憶體上限,並確保系統能保持回應性。This technique caps the maximum memory of the app and ensures the system stays responsive. 當然,您必須根據自己的案例調整傳回的檔案數目,但為了確保所有使用者都能獲得具回應性的體驗,建議您一次不要擷取超過 500 個檔案。Of course, you will need to adjust the number of files returned for your scenario, but to ensure a responsive experience for all users, it's recommended to not fetch more than 500 files at one time.

範例Example  

StorageFolder folderToEnumerate = KnownFolders.PicturesLibrary; 
// Check if the folder is indexed before doing anything. 
IndexedState folderIndexedState = await folderToEnumerate.GetIndexedStateAsync(); 
if (folderIndexedState == IndexedState.NotIndexed || folderIndexedState == IndexedState.Unknown) 
{ 
    // Only possible in indexed directories.  
    return; 
} 
 
QueryOptions picturesQuery = new QueryOptions() 
{ 
    FolderDepth = FolderDepth.Deep, 
    // Filter out all files that have WIP enabled
    ApplicationSearchFilter = "System.Security.EncryptionOwners:[]", 
    IndexerOption = IndexerOption.OnlyUseIndexerAndOptimizeForIndexedProperties 
}; 

picturesQuery.FileTypeFilter.Add(".jpg"); 
string[] otherProperties = new string[] 
{ 
    SystemProperties.GPS.LatitudeDecimal, 
    SystemProperties.GPS.LongitudeDecimal 
}; 
 
picturesQuery.SetPropertyPrefetch(PropertyPrefetchOptions.BasicProperties | PropertyPrefetchOptions.ImageProperties, 
                                    otherProperties); 
SortEntry sortOrder = new SortEntry() 
{ 
    AscendingOrder = true, 
    PropertyName = "System.FileName" // FileName property is used as an example. Any property can be used here.  
}; 
picturesQuery.SortOrder.Add(sortOrder); 
 
// Create the query and get the results 
uint index = 0; 
const uint stepSize = 100; 
if (!folderToEnumerate.AreQueryOptionsSupported(picturesQuery)) 
{ 
    log("Querying for a sort order is not supported in this location"); 
    picturesQuery.SortOrder.Clear(); 
} 
StorageFileQueryResult queryResult = folderToEnumerate.CreateFileQueryWithOptions(picturesQuery); 
IReadOnlyList<StorageFile> images = await queryResult.GetFilesAsync(index, stepSize); 
while (images.Count != 0 || index < 10000) 
{ 
    foreach (StorageFile file in images) 
    { 
        // With the OnlyUseIndexerAndOptimizeForIndexedProperties set, this won't  
        // be async. It will run synchronously. 
        var imageProps = await file.Properties.GetImagePropertiesAsync(); 
 
        // Build the UI 
        log(String.Format("{0} at {1}, {2}", 
                    file.Path, 
                    imageProps.Latitude, 
                    imageProps.Longitude)); 
    } 
    index += stepSize; 
    images = await queryResult.GetFilesAsync(index, stepSize); 
} 

結果Results 

結果的 StorageFile 檔案只會包含所要求的屬性,且相較於其他 IndexerOptions,其傳回的速度快了 10 倍。The resulting StorageFile files only contain the properties requested, but are returned 10 times faster compared to the other IndexerOptions. 應用程式仍然可以要求存取查詢中未包含的屬性,但開啟檔案並擷取那些屬性將會產生效能負面影響。 The app can still request access to properties not already included in the query, but there is a performance penalty to open the file and retrieve those properties.  

將資料夾新增到媒體櫃Adding folders to Libraries 

應用程式可以要求使用者使用 StorageLibrary.RequestAddFolderAsync (英文) 來將位置新增至索引。Apps can request the user to add the location to the index using StorageLibrary.RequestAddFolderAsync. 包含該位置之後,它會自動被編製索引,而應用程式可以使用此技巧來列舉檔案。Once the location is included, it will be automatically indexed and apps can use this technique to enumerate the files.  

另請參閱See also

QueryOptions API 參考 (英文)QueryOptions API Reference
列舉和查詢檔案和資料夾Enumerate and query files and folders
檔案存取權限File access permissions