Работа с файлами на локальном ПК и в OneDrive

OSzone.net » Microsoft » Разработка приложений » Windows (до Windows 10) » Работа с файлами на локальном ПК и в OneDrive
Автор: Марк Вотье
Иcточник: MSDN
Опубликована: 23.09.2014
Планшетные компьютеры, ставшие чрезвычайно популярными у пользователей, открыли новые возможности для мобильной работы и создания контента на ходу. Сегодня потребители хотят большего от своих планшетов: они стремятся иметь доступ к файлам с любого устройства, чтобы уменьшить объем занимаемого ими пространства в и без того небольшой по размеру памяти. В результате многие пользователи и разработчики перешли на облачные сервисы, которые предоставляют место для хранения файлов и одинаковый набор функций в любом месте и на любом устройстве.

Сервис OneDrive — важнейший компонент операционной системы Windows 8.1, обеспечивающий непревзойденную гибкость в достижении этих целей. Пользователи могут с легкостью сохранять и открывать файлы OneDrive прямо из приложений, просто выбирая файл или добавляя содержимое в свои библиотеки.  Библиотеки  позволяют эффективно агрегировать файлы, записанные на локальном ПК и в OneDrive, обеспечивая единый вход для доступа к контенту пользователя.

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

В данной статье я покажу, как быстро добавить в приложение поддержку OneDrive, не усложняя при этом существующий код. Конкретнее, я остановлюсь на следующих моментах:

  1. Основы взаимодействия с пользовательскими файлами в Windows 8.1.
  2. Интеграция OneDrive с ОС, модель данных WinRT.
  3. Обеспечение бесперебойной работы приложения в режиме онлайн и офлайн.
  4. Использование эскизов при выводе на экран изображений для достижения максимальной производительности.

О чем нужно помнить

Если вы читали мою статью о создании красивых представлений для локальных файлов или разрабатывали приложения для Windows 8, то, скорее всего, уже знакомы с методами и рекомендациями касательно доступа к файлам пользователей через WinRT API. Напомню, что получить эти файлы из приложения можно двумя способами: с помощью библиотек и средства выбора файлов.

*

Рисунок 1. Приложение Xbox Music использует возможности «Фонотеки»

*

Рисунок 2. Приложение использует средство выбора файлов для их открытия и сохранения

В Windows 8.1 приложения, использующие библиотеки, могут расширить охват содержимого с помощью управляющих API StorageLibrary. Эти промежуточные API имеют ту же функциональность, что и диалоговое окно свойств библиотеки в Проводнике, где пользователи могут добавлять и удалять папки из библиотек.

*
Увеличить

Рисунок 3. Диалоговое окно свойств библиотеки

С помощью этих новых функций пользователи могут указывать папки с фотографиями и музыкой непосредственно из приложений, работающих с мультимедийными коллекциями. Хороший пример использования API показан в приложении «Музыка».

*

Рисунок 4. Приложение «Музыка» — это точка входа в музыкальную коллекцию пользователя для добавления композиций и альбомов

*

Рисунок 5. После нажатия кнопки Add (Добавить) открывается средство библиотеки для выбора расположения

Это очень просто сделать с помощью API RequestAddFolderAsync. Данный API вызывает средство выбора расположения, чтобы пользователь выбрал папку, которую необходимо добавить в библиотеку. Средство выбора расположения отображает все ошибки напрямую, так что приложению нужно лишь обработать отмену действия. Все это легко сделать несколькими строками кода на JavaScript:

// Отображение окна выбора расположения, чтобы пользователь выбрал папку,
// которую нужно добавить в музыкальную библиотеку
function addFolder() {
  Windows.Storage.StorageLibrary.getLibraryAsync(Windows.Storage.KnownLibraryId.music).then(function (library) {
    return library.requestAddFolderAsync();
  }).done(function (folderAdded) {
    if (folderAdded !== null) {
      // Папка была добавлена в библиотеку музыки
    } else {
      // Операция была отменена
    }
  });
}

Это можно также сделать и в C#:

private async void AddFolder()
{
  StorageLibrary picturesLibrary = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Music);
  StorageFolder folderAdded = await musicLibrary.RequestAddFolderAsync();
  if (folderAdded != null)
  {
    // Папка была добавлена в библиотеку музыки
  }
  else
  {
    // Операция была отменена
  }
}

Приложение может использовать файлы, не взаимодействуя с файлами и папками пользователя , например, если оно само создает файлы для отслеживания созданного пользователем содержимого. Это могут быть стандартные изображения, аудиофайлы или специальные форматы, как в решениях для управления проектами (например, с использованием XML). Для подобного содержимого, существующего только в контексте данного приложения и бесполезного в других программах, следует использовать папки ApplicationData.

В качестве примера приведем приложение «Звукозапись». Аудиозаписи пользователя целесообразно использовать в контексте приложения, в котором они созданы, поэтому файлы хранятся в папке с данными приложения. Это лучше, чем сохранять файлы в папке «Музыка», поскольку их начинают использовать приложения типа Xbox Music, а так быть не должно. Однако пользователь иногда хочет поделиться этими файлами с коллегами или отредактировать их в приложении для обработки аудио. В таких случаях используются механизмы экспорта, описанные выше.

*
Увеличить

Рисунок 6. Все аудиофайлы приложения «Звукозапись» хранятся в папке ApplicationData

Доступ к файлам и OneDrive

Важным нововведением Windows 8.1 является глубокая интеграция OneDrive с базовыми функциями ОС. Пользователи могут хранить файлы в OneDrive так же, как и в любой системной папке, и управлять ими независимо от наличия сетевого подключения. Система сама синхронизирует файлы в фоновом режиме, процесс является полностью прозрачным для пользователя.

К OneDrive привязаны все функции системы:

*

Рисунок 8. OneDrive в средстве выбора файлов

*

Рисунок 9. OneDrive в Проводнике

Будучи разработчиком, воспринимайте файлы OneDrive как «просто файлы» — они используют тот же интерфейс StorageFile, что и другие файлы в системе, и управление ими осуществляется аналогичным образом. Но если копнуть глубже, между файлами на локальном ПК и в хранилище OneDrive есть некоторые различия. В Windows 8.1 мы ввели концепциюсмарт-файлов. Смарт-файл — это файл, который отображается в системе как обычный, но при этом хранит метаданные и эскизы, а не содержимое. Содержимое файла расположено на OneDrive и доступно для загрузки по запросу. Смарт-файлы позволяют уменьшить объем пространства, необходимого для отображения файлов OneDrive на устройстве.

Вы с этим знакомы, если пользовались контрактом выбора файлов  в Windows 8. В этом контракте пользователи могут открывать средство выбора файлов из Приложения А и выбирать файл из Приложения Б. Приложение А получает StorageFile, но он может быть на самом деле потоковым файлом, содержимое которого загружается на лету из хранилища. Смарт-файлы в OneDrive работают схожим образом: их содержимое прозрачно загружается при открытии файла. Это значит, что вам не нужно прописывать разные пути для локальных файлов и файлов OneDrive. Однако некоторые файловые операции (редактирование метаданных или копирование) будут выполняться дольше, поскольку на загрузку файла уходит больше времени, чем на его открытие с диска.

Совет. Приложения для настольных ПК могут обращаться к смарт-файлам, если используют соответствующий API. Смарт-файлы имеют атрибут LocallyIncomplete, обозначающий недоступность их содержимого в локальной среде. Приложения для настольных ПК могут определять этот атрибут и использовать интерфейс IStream для выполнения операций с такими файлами. Поскольку многие приложения Win32 используют другие API, не поддерживающие концепцию смарт-файлов, и при работе с ними могут возникать ошибки, система помечает их атрибутом system hidden (системный скрытый), чтобы предотвратить случайный доступ к ним.

Как и насколько часто использовать OneDrive, пользователь решает сам: в Windows 8.1 доступ к файлам OneDrive осуществляется через посредников, так что все всегда остается под контролем пользователя. Именно поэтому чисто программного способа получения доступа к папке пользователя в OneDrive не существует. Как правило, приложение будет сталкиваться с файлами OneDrive, если пользователь обратится к этим файлам в средстве выбора, чтобы открыть их в приложении, или если добавит папку OneDrive в библиотеку, к которой приложение имеет доступ.

Удобство работы в онлайн- и офлайн-режиме

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

*
Увеличить

Рисунок 10. Приложение OneDrive различает автономные элементы, но позволяет пользователю перемещать или удалять их

WinRT API предоставляет средства для максимально удобной работы независимо от доступности сети. Золотое правило при работе с OneDrive: программный код нужно писать только один раз, и он действует для всех типов файлов — как локальных, так и файлов в OneDrive. Типичным примером служит доступность файлов: все файлы в системе имеют свойство IsAvailable, позволяющее выяснить, есть ли доступ к содержимому файла в момент его выбора.

*
Увеличить

Таблица 1. Значения свойства IsAvailable в различных сценариях

*
Увеличить

Рисунок 11. API учитывает, что используется тарифицируемое соединение

Ниже перечислены операции, которые выполняются для всех файлов, независимо от доступности сети. В этом случае не нужно проверять свойство IsAvailable перед их выполнением:

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

Свойство IsAvailable проверяет, существует ли локальный кеш файла, подсоединен ли пользователь к сети и является ли соединение тарифицируемым, так что вы можете ни о чем не беспокоиться и сосредоточиться на своем коде. Это удобно, но вовсе не значит, что больше не нужно обрабатывать ошибки! Свойства IsAvailable оптимизировано для быстрого получения файлов, а не для поддержки их актуального состояния. Это означает, что отсутствует 100%-я гарантия доступности файла, к которому вы пытаетесь получить доступ (например, если пользователь перейдет в автономный режим вскоре после того, как вы проверите свойство). Для подобных случаев в WinRT API есть ошибка ERROR_NO_NETWORK, поэтому приложение поймет, что операция с файлом не удалась по причине отсутствия подключения к сети.

Свойство IsAvailable позволяет визуально дифференцировать элементы, недоступные в интерфейсе. Для выделения элементов используйте наложение (например, 40%-й фильтр прозрачности, как показано на снимке экрана из приложения OneDrive выше) или текст (например, строку «Недоступен» рядом с названием файла). Кроме того, на панели приложения или в контекстном меню следует отключить любые действия, которые невозможно выполнить с файлом в автономном режиме.

При запросе файла любые изменения свойства IsAvailable инициируют событие contentschanged, что позволяет обновить интерфейс и отобразить актуальное состояние каждого элемента. В JavaScript это можно сделать так:

picker.pickSingleFolderAsync().done(function (folder) {
  if (folder) {
    // Опрос папки
    var query = folder.createFileQuery();
    // Обязательно обновите представление при срабатывании события contentschanged
    var listener = function () {
      displayItems(query);
    };
    query.addEventListener("contentschanged", listener);
    // Обязательно отключите обработчик событий, когда пользователь больше не просматривает эту страницу
    WinJS.Navigation.addEventListener("navigated", function () {
      query.removeEventListener("contentschanged", listener);
    });
    // Отображение исходное представление
    displayItems(query);
  }
});

function displayItems(query) {
  query.getFilesAsync().done(function (files) {
    // Отображение списка файлов с указанием их доступности
    files.forEach(function (file) {
      // Создание записи в списке для элемента
      var list = document.getElementById("itemsList");
      var listItemElement = document.createElement("li");
      listItemElement.textContent = file.name + " (";

      // Отображение доступности элемента (элементы OneDrive доступны, если
      // находятся в режиме онлайн или помечены как «Всегда доступны в автономном режиме»)
      if (!file.isAvailable) {
        listItemElement.textContent += "not ";
      }
      listItemElement.textContent += "available)";

      list.appendChild(listItemElement);
    });
  });
}
И похожим образом в C#:
StorageFile folder = await filePicker.PickSingleFileAsync();
  if (folder != null)
  {
    // Опрос папки
    auto query = folder.CreateFileQuery();

    //Обязательно обновите представление при срабатывании события contentschanged
    var eventHandler = new TypedEventHandler<IStorageQueryResultBase, object>( (IStorageQueryResultBase sender, object args) =>
    {
      Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
      {
        displayItems();
      });
    });
    query.ContentsChanged += eventHandler;

    // Обязательно отключите обработчик событий, когда пользователь не просматривает эту страницу
    thisPage.OnNavigatedFrom += () =>
    {
      query.ContentsChanged -= eventHandler;
    }

    // Отображение исходного представления
    displayItems();
  }

private async void displayItems()
{
  IReadOnlyList<StorageFile> files = await query.GetFilesAsync();
  //Отображение списка файлов с указанием их доступности
  foreach (StorageFile file in files)
  {
    string text = "File name: " + file.Name + " (";

    // Отображение доступности элемента (элементы OneDrive доступны, если
    // находятся в режиме онлайн или помечены как «Всегда доступны в автономном режиме»)
    if (!file.IsAvailable)
    {
      text += "not ";
    }

    text += "available)";

    print(text);
  }
}

Совет. Если вы используете ListView с привязкой данных к запросу файла, то применяйте IsAvailable в модуле для рендеринга или в шаблоне, чтобы настроить представление элементов в автономном режиме. Пример можно посмотреть в приложении HiloJS на CodePlex.

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

И наконец, хотя выше и говорилось о том, что приложение не должно различать файлы OneDrive и локальные файлы, возможно, ему нужно выделять файлы из определенного источника. Например, нужно отобразить пользовательские элементы, хранящиеся в облаке, отдельно от локальных (таким образом вы покажете, что они доступны на любых устройствах, в то время как локальные — нет). В этом случае следует воспользоваться идентификатором нового свойства Provider для определения источника файла или папки. В Windows 8.1 данный идентификатор принимает одно из четырех значений:

Совет. StorageProvider имеет фиксированный идентификатор и локализованное свойство DisplayName. Удостоверьтесь, что используете идентификатор для таких операций, как сравнение (на основе порядковых номеров или нечувствительного к регистру), фильтрация и DisplayName для пользовательского интерфейса. В целом старайтесь избегать жестко прописанных идентификаторов, поскольку в будущем могут появиться новые идентификаторы.

Пример использования данного API в JavaScript:

picker.pickSingleFolderAsync().done(function (folder) {
  if (folder) {
    // Опрос папки
    var query = folder.createFileQuery();
    query.getFilesAsync().done(function (files) {
      // Отображение списка файлов с поставщиком
      files.forEach(function (file) {
        // Создание записи в списке для элемента
        var list = document.getElementById("itemsList");
        var listItemElement = document.createElement("li");
        listItemElement.textContent = file.name;

        // Отображение поставщика элемента
        listItemElement.textContent += ": On " + file.provider.displayName;
      });
    });
  }
});
//И в C#:
StorageFolder folder = await picker.PickSingleFolderAsync();
if (folder != null)
{
  // Опрос папки
  auto query = folder.CreateFileQuery();
  IReadOnlyList<StorageFile> fileList = await query.GetFilesAsync();

  // Отображение списка файлов с поставщиком хранилища и доступностью
  foreach (StorageFile file in fileList)
  {
    // Создание записи в списке для элемента
    string line = file.Name;

    // Отображение поставщика элемента (данный ПК, OneDrive, сеть или содержимое приложений)
    line += ": On " + file.Provider.DisplayName;

    OutputPanel.Children.Add(CreateLineItemTextBlock(line));
  }
}

Новый подход к отображению изображений

Отображение изображений из пользовательского содержимого — популярный способ персонализации работы пользователя и создания более привлекательного интерфейса. В большинстве случаев приложения просто получают файл и задают его в качестве источника элемента-изображения на собственном полотне. Однако этот подход не даст эффекта, если нужно просто отобразить изображение и приложение не изменяет сам файл. Для редактирования требуется доступ ко всем данным файла, но для вывода на экран нужна лишь версия изображения меньшего размера.

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

Чтобы упростить этот процесс, приложение должно использовать эскиз, а не полноразмерное изображение. Windows хранит большой кеш эскизов различного размера, а также специальные эскизы для смарт-файлов (в том числе среднего размера, которые доступны всегда, и большого размера, загружаемые в виде потока из облака). Это означает, что эскизы — лучший и самый быстрый способ получения доступных представлений изображения, не привязанных к сетевому подключению.

В Windows 8.1 максимальный размер эскиза, поддерживаемый локально и в облаке, увеличен до 1600 пикселей; этого достаточно для полноэкранного просмотра на устройствах различных формфакторов. Кроме того, для возврата уменьшенных изображений любого размера создан новый API, так что можно использовать только его, независимо от требуемого для отображения размера. API использует все имеющиеся эскизы и возвращается к самому изображению в случае, если эскизы не подходят по размеру (или к самому большому из найденных эскизов, если изображение недоступно). Возвращенный объект StorageItemThumbnail позволяет с легкостью определить, использовался ли откат.

Пример использования этого API в JavaScript:

file.getScaledImageAsThumbnailAsync(thumbnailMode, requestedSize, thumbnailOptions).done(function (thumbnail) {
  if (thumbnail) {
    // Возвращено изображение
    if (thumbnail.returnedSmallerCachedSize) {
      // Система не смогла получить изображение нужного
      // размера и возвратила доступный эскиз самого большого размера
    }
    // Вы можете легко вставить его в элемент img
    var image = document.getElementById("myImage");
    var url = URL.createObjectUrl(thumbnail, { oneTimeOnly: true });
    image.src = url;
  }
}, function (error) {
  // При получении эскиза возникла ошибка
});
//Аналогичным образом в C#:
using (StorageItemThumbnail thumbnail = await file.GetScaledImageAsThumbnailAsync(thumbnailMode, size, thumbnailOptions))
{
  if (thumbnail != null)
  {
    // Возвращено изображение
    if (thumbnail.ReturnedSmallerCachedSize) {
      // Система не смогла получить изображение нужного
      // размера и возвратила доступный эскиз самого большого размера
    }
    // Вы можете легко вставить его в элемент img
    BitmapImage bitmapImage = new BitmapImage();
    bitmapImage.SetSource(thumbnail);
    image.Source = bitmapImage;
  }
}

Благодаря этому API доступ к оригинальному файлу нужен только для редактирования, поэтому приложение будет работать максимально быстро — как в режиме онлайн, так и автономно.

Подведем итоги

В данной статье мы продемонстрировали, как тесно интегрирован OneDrive с Windows 8.1 и моделью доступа к файлам Windows 8 для приложений Магазина Windows. Несколько новых свойств существенно упрощают взаимодействие приложений со OneDrive благодаря определению доступности файла и его источника. Использование эскизов в качестве заменителей изображений позволит стабилизировать работу приложения при нестабильном сетевом подключении и быстрее отображать изображения. Большинство приложений, использующих пользовательские файлы, можно обновить с помощью нескольких строк кода, не создавая новые ветки кода для файлов OneDrive.


Ссылка: http://www.oszone.net/25238/