Состояния, параметры, файлы и документы
API средства выбора файлов и его друзья
Теперь, когда мы видели визуальную часть средства выбора файлов, посмотрим, как можно вызвать его из кода приложения с использованием API Windows.Storage.Pickers (http://msdn.microsoft.com/library/windows/apps/br207928.aspx). Все изображения, которые мы только что видели, взяты из примера "Средство выбора файлов" (http://code.msdn.microsoft.com/windowsapps/File-picker-sample-9f294cba), и мы так же используем его как источник кода.
Для начинающих, Сценарий 1 в функции pickSinglePhoto (js/scenario1.js) использует средство выбора для получения одного объекта StorageFile для открытия (чтения и записи):
function pickSinglePhoto() { // Удостоверяемся, что приложение не в прикрепленном режиме, или что мы можем перейти в иной режим для запуска // средства выбора файлов var currentState = Windows.UI.ViewManagement.ApplicationView.value; if (currentState === Windows.UI.ViewManagement.ApplicationViewState.snapped && !Windows.UI.ViewManagement.ApplicationView.tryUnsnap()) { // Не выводим дополнительных сообщений, если приложение не вышло из прикрепленного режима return; } // Создаем объект средства выбора файлов и настраиваем параметры var openPicker = new Windows.Storage.Pickers.FileOpenPicker(); openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail; openPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary; // Пользователи ожидают увидеть папки, к содержимому которых применен фильтр, который зависит от сценария. // Например, при выборе папки документов, ограничьте типы файлов документами вашего приложения openPicker.fileTypeFilter.replaceAll([".png", ".jpg", ".jpeg"]); // Открываем средство выбора файлов, чтобы позволить пользователю выбрать файл openPicker.pickSingleFileAsync().done(function (file) { if (file) { // Теперь у приложения есть доступ к выбранному файлу для чтения и записи } else { // Средство выбора файлов было закрыто без выбора файла } }); }
Как вы можете видеть, вызывать средство выбора в прикрепленном режиме не следует. Это, как и попытка вызова панели параметров, приведет к исключению. Вы можете проверить это, как показано здесь, или добавить обработчик ошибки в метод done в конце4Я должен отметить, что пример использует вместо done метод then в последнем асинхронном вызове. Хотя и then работает, там следует использовать done, особенно если вы собираетесь обрабатывать там исключения.. В любом случае, для вызова средства выбора файлов мы создаем экземпляр indows.Storage.Pickers.FileOpenPicker (http://msdn.microsoft.com/library/windows/apps/br207847.aspx), настраиваем его и затем вызываем его метод pickSingleFileAsync. Результат работы pickSingleFileAsync – это аргумент file, передаваемый в обработчик завершения, который может быть либо объектом типа StorageFile, либо содержать null, если пользователь не сделал выбор и закрыл интерфейс средства выбора файла. Именно поэтому всегда нужно проверять результат выбора файлов на null.
Настраивая средство выбора файлов, мы задали его viewMode как thumbnail (из перечисления Windows.Storage.Pickers.PickerViewMode), что привело к тому виду, который показан на рис. 2.7. Другая возможность – это list, что показано на рис. 2.10.
Кроме того, мы установили suggestedStartLocation в значение picturesLibrary, что является значением, взятым из перечисления Windows.Storage.Pickers.PickerLocationId. Другие возможности - documentsLibrary, computerFolder, desktop, downloads, homeGroup, musicLibrary, и videosLibrary, практически все остальные расположения вы можете видеть на рис. 2.8. Обратите внимание на то, что использование этих расположений не требует от вас объявления возможностей в манифесте, так как пользователь, используя средство выбора файлов, дает разрешение на доступ к этим файлам. Если вы посмотрите манифест этого примера, вы увидите, что он не объявляет никаких возможостей.
Другой свойство, которое мы задаем, это fileTypeFilter (объект FileExtensionVector (http://msdn.microsoft.com/library/windows/apps/windows.storage.pickers.fileextensionvector.aspx)), который отражает типы файлов, которые нас интересуют (PNG и JPEG). Помимо этого, FileOpenPicker так же имеет свойство commitButtonText, которое задает подпись для основной кнопки в пользовательском интерфейсе (та из них, которая не является кнопкой Отмена (Cancel), и settingsIndentifier, средство для запоминания различных контекстов для средства выбора файлов. Например, приложение может использовать один идентификатор для выбора изображений, где начальное расположение установлено на библиотеку изображений и режим просмотра – на просмотр в виде миниатюр, и другой идентификатор для выбора документов с другим начальным расположением, и, возможно, с режимом просмотра в виде списка.
Этот пример, как вы можете видеть, помимо получения файлов, ничего не делает с ними, но очень легко увидеть, что мы можем сделать с ними. Мы можем, например, просто передать StorageFile в URL.createObjectURL и присвоить результат свойству img.src для вывода изображения. То же самое можно сделать с аудио и видео-файлами, эти возможности показаны в Сценарии 1 примера "Использование больших двоичных объектов для сохранения и загрузки содержимого" (http://code.msdn.microsoft.com/windowsapps/Blob-Sample-0e35889e), о котором я говорил ранее. Этот пример так же показывает чтение содержимого файла посредством FileReader из API HTML, вместе с API WinRT и WinJS, которые мы уже видели. Так же вы можете перекодировать изображение (или другие данные), на которое ссылается StorageFile, в другой формат (мы увидим это в "Многоточечные жесты" ), получить эскиз, как показано в примере "Эскизы файлов и папок" (http://code.msdn.microsoft.com/windowsapps/File-thumbnails-sample-17575959), или использовать методы StorageFile для создания копии файла в другом расположении, переименования файла, и так далее. Но, с точки зрения средства выбора файлов, его работа здесь сделана!
Возвращаясь к примеру о средстве выбора файлов, выбор нескольких файлов, во многом – это то же самое, как показано в функции pickMultipleFiles в js/scenario2.js. Здесь мы используем режим просмотра list и начинаем просмотр с documentLibrary. Опять же, это начальное расположение не требует объявления возможностей в манифесте.
function pickMultipleFiles() { // Проверяем, не находимся ли мы в прикрепленном режиме, и так далее... (часть кода опущена) // Создаем объект средства выбора файлов и настраиваем параметры var openPicker = new Windows.Storage.Pickers.FileOpenPicker(); openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.list; openPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.documentsLibrary; openPicker.fileTypeFilter.replaceAll(["*"]); // Открываем средство выбора файлов, чтобы позволить пользователю выбрать файл openPicker.pickMultipleFilesAsync().done(function (files) { if (files.size > 0) { // Теперь у приложения есть доступ к выбранному файлу (файлам) для чтения и записи } else { // Средство выбора файлов было закрыто без выбора файла } }); }
При выборе нескольких файлов, результат pickMultipleFilesAsync – это объект FilePickerSelectedFilesArray (http://msdn.microsoft.com/library/windows/apps/windows.storage.pickers.filepickerselectedfilesarray.aspx), доступ к которому осуществляется как к любому другому массиву, с использованием [ ] (хотя у него меньше методов, чем у обычного массива).
Сценарий 3 примера демонстрирует вызов pickSingleFolderAsync, результат этой операции – объект StorageFolder. Здесь вы должны задать fileTypeFilter, что поможет пользователям выбрать подходящее расположение, в котором существуют файлы нужного типа, или то, где они смогут создать новые подобные файлы (js/scenario3.js):
function pickFolder() { // Проверяем, не находимся ли мы в прикрепленном режиме, и так далее... (часть кода опущена) // Создаем объект средства выбора файлов и настраиваем параметры var folderPicker = new Windows.Storage.Pickers.FolderPicker; folderPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.desktop; folderPicker.fileTypeFilter.replaceAll([".docx", ".xlsx", ".pptx"]); folderPicker.pickSingleFolderAsync().then(function (folder) { if (folder) { // Кэшируем папку, таким образом позже мы сможем получить доступ к ее содержимому Windows.Storage.AccessCache.StorageApplicationPermissions.futureAccessList .addOrReplace("PickedFolderToken", folder); } else { // Средство выбора файлов было закрыто без выбора объекта } }); }
В этом примере мы так же видим, как сохранить выбранный объект StorageFolder в Windows.Storage.AccessCashe (http://msdn.microsoft.com/library/windows/apps/windows.storage.accesscache.aspx) для последующего использования. Опять же, выбирая эту папку, пользователь дает приложению программный доступ к ее содержимого, но только на время текущего сеанса работы. Для того, чтобы сохранить полученные права, приложение должно записать элемент хранения в futureAccessList, в кэш, откуда эти данные могут быть извлечены позже, с использованием методов futureAccessList.getFolderAsync, getItemAsync, или getFileAsync. Как и ранее, обратитесь к Сценарию 6 примера "Доступ к файлу" (http://code.msdn.microsoft.com/windowsapps/File-access-sample-d723e597) для того, чтобы больше узнать об этой возможности, и обратите внимание на то, что API AccessCache так же можно применять для недавно использованных элементов. Ключевая вещь, которую нужно здесь запомнить, заключается в том, что для любого расположения за пределами пакета приложения, данных приложения, или библиотек, доступ к которым вы объявили в манифесте, вы должны использовать AccessCashe для того, чтобы подобный доступ был у вас в будущем. Обычное сохранение пути к расположению и попытка открыть файлы из него позже не дадут результата.
Последний пример использования средства выбора файлов, в Сценарии 4 примера, создается объект FileSavePicker (http://msdn.microsoft.com/library/windows/apps/br207871.aspx) и вызывается метод pickSaveAsync, что приводит к появлению интерфейса, показанного на рис. 2.12:
function saveFile() { // Проверяем, не находимся ли мы в прикрепленном режиме, и так далее... (часть кода опущена) // Создаем объект средства выбора файлов и настраиваем параметры var savePicker = new Windows.Storage.Pickers.FileSavePicker(); savePicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.documentsLibrary; // Выпадающий список типов файлов, применимый при сохранении savePicker.fileTypeChoices.insert("Plain Text", [".txt"]); savePicker.pickSaveFileAsync().done(function (file) { if (file) { // Предотвращает обновление удаленной версии файла до тех пор, пока мы не завершим // изменения и не вызовем CompleteUpdatesAsync. Windows.Storage.CachedFileManager.deferUpdates(file); // записываем в файл Windows.Storage.FileIO.writeTextAsync(file, file.name).done(function () { // Дадим Windows знать, что мы завершили изменение файла и другие приложения // могут обновлять удаленную версию файла. // Завершение обновлений может потребовать у Windows запросить у пользователя ввод данных. Windows.Storage.CachedFileManager.completeUpdatesAsync(file) .done(function (updateStatus) { if (updateStatus === Windows.Storage.Provider.FileUpdateStatus.complete) { } else { // ... } } }); }); } else { // Интерфейс был закрыт } }); }
У объекта FileSaverPicker есть множество тех же свойств, что и у FileOpenPicker, но fileTypeFilter заменен на fileTypeChoices (для заполнения выпадающего списка), так же имеются свойства suggestedFileName (строка), suggestedSaveFile (объект StorageFile), и defaultFileExtension (строка). На что интересно взглянуть в вышеприведенном коде, так это на взаимодействие с Windows.Storage.CachedFileManager (http://msdn.microsoft.com/library/windows/apps/windows.storage.cachedfilemanager.aspx). Этот объект помогает поставщику средства выбора файлов узнать, следует ли ему синхронизировать локальные файлы и файлы, хранящиеся на удаленном сервисе, что необходимо, когда пользователь файла сохраняет новое содержимое, как мы видим здесь. Со стороны потребителя, то, что мы здесь видим – это обычный шаблон для работы с файлами, полученными от средства выбора файлов (или из кэша доступа, если эти данные были сохранены в предыдущих сеансах работы): нам просто нужно дать знать объекту CashedFileManager, что мы осуществляем запись в файл, и сообщить ему, когда сделаем это. Конечно, этого делать не нужно, когда вы работаете с файлами, о которых вы знаете, что они локальные, как с теми, которые находятся в папках, расположенных в AppData. Больше об этом механизме мы узнаем в лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой", посмотрим на него со стороны поставщика.
Медиабиблиотеки
Теперь, когда мы познакомились с возможностями средства выбора файлов, мы можем направить внимание на библиотеки. Но прежде чем мы начнем проверять возможности, заявленные в манифесте, остановимся на мгновение для того, чтобы спросить себя: нужны ли эти возможности на самом деле. Средство выбора файлов предоставляет весьма широкий доступ ко всем библиотекам без необходимости объявления каких-либо возможностей. С помощью средства выбора файлов, мы можете позволить пользователю выбрать один или несколько файлов для открытия, управления и сохранения, а пользователь может предоставить вам доступ к папке. И пользователь может указать новое имя файла для сохранения пользовательских данных.
Вам нужен доступ к определенной библиотеке, если вы собираетесь работать с ней вне средства выбора файлов. Например, если вы хотите перебрать содержимое папок Изображения или Музыка для того, чтобы отобразить список файлов в элементе управления ListView или FlipView, как мы делали в лекции курса "Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript", вам нужно объявлять возможности.
Чтобы быть более конкретным, без использования средства выбора файлов, это – единственный способ получить программный доступ к медиабиблиотекам: получения объекта StorageFolder из объекта Windows.Storage.KnownFolders (http://msdn.microsoft.com/library/windows/apps/windows.storage.knownfolders.aspx). В случае с медиаданными, применимые возможности здесь – picturesLibrary, musicLibrary и videoLibrary. Без объявления соответствующих возможностей, попытка получить одно из этих значения приведет к исключению отказа в доступе.
Если вы не собираетесь пользоваться KnownFolders, это означает, что вам не нужно объявлять возможности! Помните, что объявленные возможности перечислены на странице приложения в Магазине Windows и могут вызвать у пользователя размышления о том, стоит ли устанавливать ваше приложение, поэтому, чем меньше возможностей будет объявлено – тем лучше.
Тем не менее, если вы решите, что вам нужен прямой доступ к медиа-библиотекам, работа с ними включает в себя объекты StorageFolder и StorageFile так же, как при работе с любым другим расположением. Единственная разница, однако, это то, что вы можете работать с метаданными, которые часто существуют вместе с медиафайлами, подробнее об этом мы поговорим в "Многоточечные жесты"
Документы и съемные носители
Как и в случае с доступом к папкам с медиаданными, программный доступ к папке с документами пользователя, так же, как и к съемным носителям, контролируется через объявление возможностей. Важно понимать и то, что обе эти возможности так же требуют, чтобы вы объявили сопоставление типов файлов, что означает, что вы не можете просто просмотреть содержимое папки напрямую, или записать в нее любой файл, какой захотите. Иными словами, получать непосредственный доступ к этим папкам с помощью Windows.Storage.KnownFolders.documentsLibrary и removableDevices, где и то и другое является объектом StorageFolder – просто для работы с ограниченным набором типов файлов, полезно лишь при реализации некоторых сценариев. Для библиотеки документов, на самом деле, документация говорит о том, что "единственное приемлемое использование [возможности] – это поддержка открытия содержимого, внедренного в другие документы". Магазин Windows так же требует оправданного использования объявления возможностей и так же требует, чтобы у вас была корпоративная учетная запись в Магазине Windows, а не только учетная запись индивидуального разработчика.
Более вероятно, что вы просто хотите позволить пользователю открывать или сохранять файлы в этих расположениях или просматривать их содержимое, а в подобных случаях все, что вам нужно – это средство выбора файлов. При таком подходе вам не нужно связывать ваше приложение с определенными типами файлов, что так же говорит о том, что ваше приложение сможет работать с подобными файлами в любое время.
Например, в примере "Съемные носители информации" (http://code.msdn.microsoft.com/windowsapps/Removable-Storage-52cc49f0), для демонстрации доступа к съемным носителям информации, объявляются сопоставления с .gif, .jpg и .png-файлами. В результате, приложение отображается в списке Открыть с помощью… (Open With) в контекстном меню, в Проводнике Windows на Рабочем столе, и в средстве выбора программ по умолчанию:
То же самое справедливо и для документов (снова посмотрите пример Доступ к файлам" ( http://code.msdn.microsoft.com/windowsapps/File-access-sample-d723e597)), таким образом, если ваше приложение не позиционируется как приложение для работы с подобными файлами, вам, возможно, не нужны эти возможности.
На самом деле, объявление сопоставления типов файлов, это разновидность контрактов, мы рассмотрим это подробно в лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой".