快速存取 UWP 中的檔案屬性
了解如何從程式庫快速收集檔案和其屬性的清單,並在應用程式中使用那些屬性。
必要條件
- 適用於通用 Windows 平台 (UWP) 應用程式的非同步程式設計 您可以參閱在 C# 或 Visual Basic 中呼叫非同步 API \(部分機器翻譯\),以了解如何在 C# 或 Visual Basic 中撰寫非同步應用程式。 若要了解如何使用 C++ 撰寫非同步的應用程式,請參閱 C++ 的非同步程式設計。
- 針對程式庫的存取權限 這些範例中的程式碼需要 picturesLibrary 功能,但是您的檔案位置可能需要其他功能,或不需要任何功能。 若要深入了解,請參閱檔案存取權限。
- 簡易檔案列舉 此範例使用 QueryOptions \(英文\) 來設定幾個進階列舉屬性。 若要深入了解僅取得小型目錄的簡易檔案清單,請參閱列舉和查詢檔案和資料夾 \(部分機器翻譯\)。
使用方式
有許多應用程式都需要列出一組檔案的屬性,但不一定需要與那些檔案直接互動。 例如,某個音樂應用程式一次會播放 (開啟) 一個檔案,但它需要資料夾中所有檔案的屬性,好讓應用程式可以顯示歌曲佇列,或讓使用者可以選擇有效檔案來播放。
此頁面上的範例不應用於會修改每個檔案的中繼資料,或是會與所有產生的 StorageFiles 進行讀取屬性以外之互動行為的應用程式。 如需詳細資訊,請參閱列舉和查詢檔案和資料夾 \(部分機器翻譯\)。
列舉某個位置中的所有圖片
在此範例中,我們將
- 建置 QueryOptions \(英文\) 物件來指定應用程式想要盡快列舉檔案。
- 透過將 StorageFile 物件分頁至應用程式來擷取檔案屬性。 對檔案進行分頁可以降低應用程式所使用的記憶體,並改善其使用者所體驗到的回應性。
建立查詢
若要建置查詢,我們會使用 QueryOptions 物件來指定應用程式有興趣只列舉特定類型的影像檔案,並篩選掉受到 Windows 資訊保護 (System.Security.EncryptionOwners) 所保護的檔案。
請務必使用 QueryOptions.SetPropertyPrefetch(英文\) 來設定應用程式將會存取的屬性。 如果應用程式存取未預先擷取的屬性,將會產生顯著的效能負面影響。
設定 IndexerOption.OnlyUseIndexerAndOptimzeForIndexedProperties \(英文\) 會告知系統盡快傳回結果,但僅包含在 SetPropertyPrefetch \(英文\) 中所指定的屬性。
在結果中進行分頁
使用者的圖片媒體櫃中可能會有上百萬個檔案,因此呼叫 GetFilesAsync \(英文\) 將會使其電腦無法負擔,因為它會為每個影像建立 StorageFile。 解決方法是一次建立固定數量的 StorageFiles,將它們處理至 UI,然後釋放記憶體。
在我們的範例中,我們的做法是使用 StorageFileQueryResult.GetFilesAsync(UInt32 StartIndex, UInt32 maxNumberOfItems) \(英文\) 來一次僅擷取 100 個檔案。 應用程式接著會處理檔案,並允許作業系統隨後釋放記憶體。 此技巧會限制應用程式的記憶體上限,並確保系統能保持回應性。 當然,您必須根據自己的案例調整傳回的檔案數目,但為了確保所有使用者都能獲得具回應性的體驗,建議您一次不要擷取超過 500 個檔案。
範例
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);
}
結果
結果的 StorageFile 檔案只會包含所要求的屬性,且相較於其他 IndexerOptions,其傳回的速度快了 10 倍。 應用程式仍然可以要求存取查詢中未包含的屬性,但開啟檔案並擷取那些屬性將會產生效能負面影響。
將資料夾新增到媒體櫃
應用程式可以要求使用者使用 StorageLibrary.RequestAddFolderAsync \(英文\) 來將位置新增至索引。 包含該位置之後,它會自動被編製索引,而應用程式可以使用此技巧來列舉檔案。
另請參閱
QueryOptions API 參考 \(英文\)
列舉和查詢檔案和資料夾
檔案存取權限