Быстрый доступ к свойствам файлов в UWP

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

Предварительные требования

  • Асинхронное программирование для приложений универсальной платформы Windows (UWP). Узнайте, как создавать асинхронные приложения на C# или Visual Basic, изучив статью Вызов асинхронных API в C# и Visual Basic. Сведения о написании асинхронных приложений в C++см. в статье "Асинхронное программирование" в C++
  • Права доступа к библиотекам. Коду в этих примерах требуется возможность picturesLibrary. Для вашего расположения файла может потребоваться другая возможность либо вообще не потребоваться никаких возможностей. Дополнительные сведения см. в разделе "Разрешения на доступ к файлам". 
  • Простое перечисление файлов. В этом примере QueryOptions используется для настройки нескольких расширенных свойств перечисления. Чтобы узнать больше о том, как получить простой список файлов для небольшого каталога, ознакомьтесь с разделом Перечисление файлов и папок и адресация им запросов

Употребление

Многим приложениям требуется отобразить список свойств группы файлов, но не всегда требуется напрямую взаимодействовать с файлами. Например, музыкальное приложение воспроизводит (открывает) по одному файлу за раз, но ему требуются свойства всех файлов в папке, чтобы можно было отобразить очередь композиций или чтобы пользователь мог выбрать действительный файл для воспроизведения.

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

Перечисление всех рисунков в расположении

В этом примере мы сделаем следующее:

  • создадим объект QueryOptions, чтобы указать, что приложению требуется как можно скорее перечислить файлы;
  • найдем свойства файлов, выполнив постраничную подкачку объектов StorageFile в приложение. Постраничная подкачка файлов позволяет уменьшить объем используемой приложением памяти и повышает скорость его реагирования.

Создание запроса

Чтобы создать запрос, мы используем объект QueryOptions, который позволяет указать, что приложению нужно перечислить только определенные типы файлов изображений или отфильтровать файлы, защищенные системой Windows Information Protection (System.Security.EncryptionOwners). 

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

Настройка свойства IndexerOption.OnlyUseIndexerAndOptimzeForIndexedProperties указывает системе на то, что вернуть результаты нужно как можно скорее, однако включить в них нужно только свойства, заданные в методе SetPropertyPrefetch.

Разбиение по страницам в результатах

В библиотеке изображений пользователей могут храниться тысячи и миллионы файлов, поэтому при вызове метода GetFilesAsync компьютер пользователя будет перегружен, потому что для каждого изображения создается файл StorageFile. Чтобы решить эту проблему, можно однократно создать фиксированное количество файлов StorageFiles, обработать их в пользовательском интерфейсе, а затем освободить память. 

В нашем примере для этого используется метод 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 содержат только запрошенные свойства, но возвращаются в 10 раз быстрее по сравнению с другими вариантами IndexerOptions. Приложение в любом случае может запросить доступ к свойствам, которые не включены в запрос, однако при открытии файла и извлечении этих свойств снижается производительность.  

Добавление папок в библиотеки

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

См. также

Справочные материалы по API QueryOptions
Перечисление и запрос файлов и папок
Разрешения на доступ к файлам