Опубликован: 10.04.2013 | Доступ: свободный | Студентов: 440 / 9 | Длительность: 16:52:00
Специальности: Программист
Лекция 2:

Состояния, параметры, файлы и документы

Расширенные возможности запросов к файлам

Для того чтобы перечислить файлы в определенном расположении (помимо возможностей), вы используете то, что называется файловым запросом (file query), или просто, поиском. Файловый запрос – это то, что Проводник Windows на рабочем столе использует для поиска по файловой систем, и может включать в себя поиск по содержимому файла, так же, как любое количество других свойств и метаданных. Эти запросы используют то, что называется строками Advanced Query Syntax (AQS) (http://msdn.microsoft.com/library/windows/desktop/bb266512.aspx) и могут идентифицировать и описать столько специфических критериев, сколько вам нужно. Вся эта тема несколько не вписывается в рамки курса, но мы можем, по крайней мере, взглянуть на то, как WinRT предоставляет богатые возможности файловых запросов приложениям посредством Windows.Storage.Search (http://msdn.microsoft.com/library/windows/apps/br208106.aspx). Достаточно будет заглянуть в глубокую кроличью нору!

На самом деле, существуют буквально тысячи параметров, которые можно использовать в AQS-строках, так как они могут быть построены из любого количества свойств Windows (http://msdn.microsoft.com/library/windows/desktop/dd561977.aspx), таких, как System.ItemDate, System.Author, System.Keywords, System.Photo.LightSource и так далее 5 Вопреки любым примерам в документации, в запросах всегда следует использовать полные имена свойств Windows, как, например System.ItemDate:, вместо удобного для программистов сокращения date:, так как последний вариант не будет работать в локализованных версиях Windows. . Каждое из свойств может содержать целевое значение, такое, как System.Author(Patrick or Bob) и System.ItemType: "mp3", и условия могут объединяться с помощью операторов AND, OR и NOT. Больше примеров мы увидим в "Многоточечные жесты" , где мы будем использовать запросы для получения коллекций файлов во множестве различных "форм", например, в виде одномерного списка, в иерархическом виде, в различных вариантах сортировки, включая те, которые основаны на медиа-свойствах. В дополнение, файловые запросы так же позволяют получать эскизы и автоматически получать альбомную графику для музыкальных произведений.

Сконцентрируемся теперь на основных принципах работы файловых запросов, начнем с основ, которые показаны в упражнении FileQuery, которое включено в материалы к этой лекции. Это упражнение – копия примера "Программный поиск файлов" (http://code.msdn.microsoft.com/windowsapps/Programmatically-searching-25e1a56b) из Windows SDK, там присутствует лишь один сценарий, ориентированный на музыкальную библиотеку, который позволяет вам непосредственно вводить AQS-строку. Однако, это не то, что вы всегда будете использовать в приложениях, поэтому я хочу показать вам и другие варианты.

Запросы всегда начинаются со StorageFolder (http://msdn.microsoft.com/library/windows/apps/br227230.aspx), методы которого createFileQuery[WithOptions], createFolderQuery[WithOptions] , и createItemQuery[WithOptions] (всего 6) используются для перечисления файлов, папок, или и того и другого в заданной папке StorageFolder . Простейшие запросы создают на основе методов StorageFolder.create* без параметров:

folder.createFileQuery(); 
folder.createFolderQuery(); 
folder.createItemQuery(); 

Здесь первые два метода – это лишь сокращения для варианта с одним параметром с одним и тем же именем, где параметр – это значение из перечисления Windows.Storage.Search.CommonFileQuery (http://msdn.microsoft.com/library/windows/apps/windows.storage.search.commonfilequery.aspx) или CommonFolderQuery (http://msdn.microsoft.com/library/windows/apps/windows.storage.search.commonfolderquery.aspx). Эти короткие имена просто используют значение defaultQuery для обычного перечисления всего содержимого папки в алфавитном порядке. В свою очередь, createItemQuery имеет лишь эту единственную форму.

Само по себе создание запроса ничего не перечисляет до тех пор, пока вы не запросите перечисление посредством асинхронного метода: для файловых запросов это метод getFilesAsync, для папок – getFoldersAsync, а для элементов хранения – getItemsAsync (Видите здесь повторяющуюся последовательность?). Таким образом, в Сценарии 2 упражнения FileQuery, у меня есть все три функции, подключенные к кнопкам:

function fileQuery() {	
var query = picturesLibrary.createFileQuery();
SdkSample.showResults(query.getFilesAsync());	
}	

function folderQuery() {	
var query = picturesLibrary.createFolderQuery();
SdkSample.showResults(query.getFoldersAsync());	
 }

function itemQuery() {
var query = picturesLibrary.createItemQuery();
SdkSample.showResults(query.getItemsAsync());
}	
 

Здесь функция SdkSample.showResults в js/default.js просто создает список элементов в коллекции. Запустив этот пример, вы увидите список файлов или папок в вашей библиотеке изображений.

Совет. Реальный тип объектов, возвращаемый API create*Query, это StorageFileQueryResult, StorageFolderQueryResult, и StorageItemQueryResult, все они находятся в пространстве имен Windows.Storage.Search. Все они предоставляют некоторые дополнительные свойства, наподобие folder, методы наподобие findStartIndexAsync и getItemCountAsync, и события вроде optionschanged and contentschanged (оба - события WinRT). Последнее событие – это то, что вы можете использовать для отслеживания изменений в файловой системе, которые воздействуют на результаты запроса.

Помимо получения неглубокого (shallow) представления, запросы к файлам и папкам имеют множество других возможностей, которые отражены в перечислениях CommonFileQuery и CommonFolderQuery:

  • В CommonFileQuery это: orderByName (порядок по имени), orderByTitle (порядок по заголовку), orderByDate (порядок по дате), orderByMusicProperties (порядок по свойствам аудиозаписи), и orderBySearchRank (порядок по рейтингу поиска).
  • В CommonFolderQuery это : groupByType (группировка по типу), groupByTag (группировка по тегу), groupByAuthor (группировка по автору), groupByYear (группировка по году), groupByMonth (группировка по месяцу), groupByArtist, groupByComposer (группировка по композитору), groupByGenre (группировка по жанру), groupByPublishedYear (группировка по жанру публикации), и groupByRating (группировка по рейтингу).

Очевидно, что эффект указания этих вариантов зависит от того, имеются ли у запрошенных элементов метаданные, которые поддерживают соответствующую группировку или упорядочение, но можно выполнить запрос ко всем папкам для всех типов файлов и папок. Для демонстрации этого Сценарий 3 упражнения FileQuery позволяет вам выбирать библиотеку музыки, изображений или видео. Затем вы можете выбрать, нужно ли строить запрос по файлам или папкам, указывать общепринятые параметры и запускать поиск для того, чтобы получить результат. Обратите внимание на то, что использование orderBySearchRank с файлами не имеет смысла в этом контексте, так как это предназначено для поисковых запросов, основанных на AQS. Мы увидим еще кое-что об этом позже (Кроме того – можете назвать меня бездельником! – результыты сгруппированного запроса к папке не особенно интересны, когда не выводятся в некие экранные элементы, но пример реализации подобного механизма вы можете увидеть в Сценарии 2 примера "Перечисление папок" (http://code.msdn.microsoft.com/windowsapps/Folder-enumeration-sample-33ebd000)). Код в js/scenario3.js, в основном, реализует механизм отображения выделенных элементов пользовательского интерфейса в createFileQuery или createFolderQuery с верными параметрами, таким образом вам не нужно просматривать большую их часть. Один важный участок кода – это использование методов isCommonFileQuerySupported и isCommonFolderQuerySupported объекта StorageFolder. Они используются для проверки того, поддерживает ли текущая папка тот запрос, который вы пытаетесь выполнить:

if (folder.isCommonFileQuerySupported(selectedQuery)) {
query = folder.createFileQuery(selectedQuery);	
if (query) {	
promise = query.getFilesAsync();	
}	
}	
 

Вы обнаружите, исполняя примеры в медиа-библиотеках, что все обычные запросы для папок и файлов поддерживаются ими, но это может быть не так для всех объектов StorageFolder, с которыми вы можете встретиться. Помните, например, что средство выбора папок может предоставить вам объект StorageFolder от поставщика, данные которого находятся на каком-нибудь онлайновом сервисе или в базе данных, в таком случае некоторые запросы могут не работать.

Похожий метод, StorageFolder.areQueryOptionsSupported, существует для проверки, поддерживаются ли пользовательские запросы, помимо стандартных. Пользовательский запросы описываются с помощью объекта Windows.Storage.Search.QueryOptions (http://msdn.microsoft.com/library/windows/apps/windows.storage.search.queryoptions.aspx) (стандартные запросы – это лишь предварительно заполненные экземпляры этого объекта) и создаются путем передачи этого объекта в createFileQueryWithOptions, createFolderQueryWithOptions, и createItemQueryWithOptions.

Объект QueryOptions обычно создается с нуля, с использованием оператора new, после чего вы заполняете его свойства. Так же вы можете использовать new QueryOptions(<CommonFolderQuery>) для получения объекта для одного из обычных запросов к папкам, и new QueryOptions(<CommonFileQuery> [, <file type filter>]) для того, чтобы сделать то же самое для файловых запросов. В последнем случае можно передать необязательный массив типов файлов. Это – короткое имя для часто настраиваемого стандартного запроса с особым набором типов файлов. Без него, фильтр установлен в"*" по умолчанию. Таким образом, если вам просто нужно найти .mp3-файлы в вашей музыкальной библиотеке, упорядоченные по заголовку (title), вы можете использовать что-то вроде нижеприведенного кода (смотрите js/scenario4.js в упражнении FileQuery):

var musicLibrary = Windows.Storage.KnownFolders.musicLibrary;
var options = new Windows.Storage.Search.QueryOptions( Windows.Storage.Search.CommonFileQuery.orderByTitle, [".mp3"]);

if (musicLibrary.areQueryOptionsSupported(options)) {	
var query = musicLibrary.createFileQueryWithOptions(options);
SdkSample.showResults(query.getFilesAsync());	
}	
 

Если вы создаете QueryOptions с нуля, вы можете настроить множество параметров. Вот основные параметры :6Другое свойство, <code> dateStackOption</code> (значение из <code>Windows.Storage.Search.DateStackOption</code>), в данной структуре представлено в виде только для чтения, но оно может быть установлено при создании <code>QueryOptions</code>; из CommonFolderQuery. :

  • fileTypeFilter вектор из строк, который описывает желаемые расширения типов файлов, такие, как ".mp3". Значение по умолчанию – пустой список (фильтрация не применяется).
  • folderDepth принимает либо значение Windows.Storage.Search.FolderDepth.shallow (по умолчанию, неглубокое представление содержимого ), либо deep (глубокое рекурсивное представление всех вложенных папок и файлов.
  • indexerOption значение из Windows.Storage.Search.IndexerOption, оно может быть одним из следующих: useIndexerWhenAvailable, onlyUseIndexer (ограничивает поиск индексированным содержимым), и doNotUseIndexer (запрос направлен напрямую на файловую систему, без использования индекса). Последний вариант по умолчанию, обычно данное свойство явно устанавливают в значение useIndexerWhenAvailable.
  • sortOrder вектор из структур Windows.Storage.Search.SortEntry, каждая из которых содержит булево значение с именем ascendingOrder (значение false для убывающего порядка) и строку propertyName. Каждая запись в векторе определяет критерий сортировки. Эти критерии применяются в том порядке, в котором они расположены в векторе. Пример этого будет дан немного позже.

Три свойства QueryOptions затем примняются к поиску с AQS-строками:

  • applicationSearchFilter – AQS-строка.
  • userSearchFilter – другая AQS-строка.
  • language строка, содержащая идентификатор языка BCP-47, связанный с AQS-строками.

Когда запрос построен с помощью метода, наподобие createFileQueryWithOptions, строки пользовательского фильтра и фильтра приложения комбинируются. Это означает, что вы можете раздельно управлять любым фильтром, который вы хотите применять везде в вашем приложении (applicationSearchFilter) с помощью условий поиска, заданных пользователем (userSearchFilter). Таким образом, вы можете применить некоторые поисковые фильтры без необходимости ввода их пользователем, и без того, чтобы всегда выполнять объединение их со строками, заданными вами.

Как упоминалось выше, запрос CommonFileQuery.orderBySearchRank имеет смысл лишь тогда, когда он скомбинирован с AQS-строкой, что говорит о том, что поиск, основанный на ключевых словах, возвращает ранжированный результат, к которому может быть применен обычный файловый запрос. Возвращаясь к Сценарию 1 примера о программном поиске файлов, мы можем увидеть, как здесь используется такое упорядочение вместе со свойством userSearchFilter:

var musicLibrary = Windows.Storage.KnownFolders.musicLibrary;	
var options = new Windows.Storage.Search.QueryOptions(	
Windows.Storage.Search.CommonFileQuery.orderBySearchRank, ["*"]);
options.userSearchFilter = searchFilter;	
var fileQuery = musicLibrary.createFileQueryWithOptions(options);	
 

На моем компьютере, где у меня есть несколько музыкальных композиций со словом "Nightingale" в заголовке, где есть и альбом, названный "Nightingale Lullaby", поиск с использованием строки "Nightingale" System.ItemType: "mp3" в вышеприведенном коде, дает мне следующий результат:


Здесь можно видеть, что при поисковом ранжировании отобраны предпочитаемые композиции с "Nightingale" в заголовке, но так же в поиск включены композиции из альбома, который имеет это слово в имени.

Моя поисковая строка, кстати, показывает, как вы можете использовать свойства applicationSearchFilter и userSearchFilter вместе. Если мое приложение может работать только с mp3 или с некоторыми другими форматами, я могу сохранить "System.Item.Type: 'mp3'" в applicationSearchFilter, а условия, которые задает пользователь, в userSearchFilter. Тем самым я избегаю самостоятельного объединения этих условий в коде.

Помимо свойств, которые устанавливают в объекте QueryOptions существуют некоторые данные и возможности этого объекта. Так, groupPropertyName, это строковое свойство, которое показывает тип свойства, по которому будет сгруппирован запрос. Так же вы можете получить параметры запроса в виде строки, используя метод saveToString и создать объект на основе строки, используя loadFromString (это – аналог JSON.stringify и JSON.parse).

Метод setPropertyPrefetch идет даже глубже, позволяя вам указать группу свойств файла, которую вы хотите оптимизировать для быстрого поиска. Доступ к ним осуществляется через те же API, что и к другим свойствам, но результаты возвращаются быстрее. Это означает, что если вы отображаете коллекцию файлов в ListView, используя пользовательский источник данных с определенными свойствами из полученных файлов, вы можете установить для этих свойств выборку с упреждением (prefetch), и, в итоге, элемент управления быстрее выведет данные. (WinJS.UI.StorageDataSource уже это делает). Похожим образом, setThumbnailPrefetch сообщает Windows о том, эскизы (thumbnails) какого рода вы хотите включить в полученные результаты – опять же, вы можете запросить их, не устанавливая выборку с упреждением, но когда вы это делаете, вы получаете их быстрее. Это помогает вам оптимизировать визуализацию коллекции файлов7Посмотрите материал "Изменения, представляющие интерес для разработчиков приложений, внесенные после выхода Consumer Preview" (http://blogs.msdn.com/b/windowsappdev_ru/archive/2012/06/07/consumer-preview.aspx) в блоге для разработчиков приложений для Windows 8 для того, чтобы узнать некоторые подробности об этом. .

В лекции 5 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", мы уже видели пример похожего использования свойств, связанных с эскизами, когда пользовались коротким именем библиотеки изображений с WinJS.UI.StorageDataSource и могли задавать параметр, указывающий размер эскиза:

myFlipView.itemDataSource = new WinJS.UI.StorageDataSource("Pictures",
{ requestedThumbnailSize: 480 });
 

Более общий пример, который так же включает вектор QueryOptions.sortOrder, можно найти в примере "Использование StorageDataSource и GetVirtualizedFilesVector" (http://code.msdn.microsoft.com/windowsapps/Data-source-adapter-sample-3d32e535), который упомянут в лекции 5 курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript". В примере, в js/scenario2.js, мы можем видеть создание QueryOptions с нуля, установку двух критериев sortOrder, и задание параметров эскизов в источнике данных:

function loadListViewControl() {
// Создаем источник данных из библиотеки изображений
var library = Windows.Storage.KnownFolders.picturesLibrary;
var queryOptions = new Windows.Storage.Search.QueryOptions;
// Неглубокий запрос для получения иерархии файлов
queryOptions.folderDepth = Windows.Storage.Search.FolderDepth.shallow;
queryOptions.sortOrder.clear();
// Упорядочиваем элементы по типу, таким образом, первыми идут папки 
queryOptions.sortOrder.append({ascendingOrder: false, propertyName: "System.IsFolder"}); 
queryOptions.sortOrder.append({ascendingOrder: true, propertyName: "System.ItemName"}); 
queryOptions.indexerOption =
Windows.Storage.Search.IndexerOption.useIndexerWhenAvailable;

var fileQuery = library.createItemQueryWithOptions(queryOptions);	
var dataSourceOptions = {	
mode: Windows.Storage.FileProperties.ThumbnailMode.picturesView,	
requestedThumbnailSize: 190,	
thumbnailOptions: Windows.Storage.FileProperties.ThumbnailOptions.none
};	

var dataSource = new WinJS.UI.StorageDataSource(fileQuery, dataSourceOptions);

// Создаем ListView...
};
 

Если вам хочется разобраться с этим глубже, вы можете посмотреть, как заданы файловые запросы в StorageDataFolder. Просто найдите этот класс в файле ui.js в WinJS. По пути вы столкнетесь с другим набором API WinRT – возможно, это – дно кроличьей норы. Я хочу упомянуть о них, прежде чем рассматривать эту тему: Windows.Storage.BulkAccess. Они действительно существуют исключительно для использования в StorageDataSource и не предназначены для прямого использования в приложениях. Даже если вы создадите собственный источник данных или элемент управления коллекцией, лучше всего – использовать средства перечисления и API для упреждающей выборки данных, о которых мы уже говорили, так как они дают такой же уровень производительности.

Вадик Елетин
Вадик Елетин
Россия, г. Санкт-Петербург
Николай Жигульский
Николай Жигульский
Россия, Тверь, Тверской государственный технический университет