В этой статье мы рассмотрим возможности платформы Windows Phone 7 по хранению данных в приложении.

В общем и целом, имеется три способа хранения данных:

  1. Isolated Storage File. Это специально отведённое место в телефоне для хранения информации под конкретное приложение. Представляет собой простую файловую систему с папками и файлами. У каждого приложения имеется своё изолированное хранилище и доступ к этому хранилищу может получить только его хозяин.
  2. Isolated Storage Settings. Это возможность хранить данные в виде пары ключ-значение. Идеально подходит для хранения каких-то настроек приложения, что впрочем и так понятно из названия ☺. Хранится, кстати говоря, в корне Isolated Storage File, файл называется __ApplicationSettings.
  3. DataContext. Это возможность «прикрутить» к своему приложения реляционную базу данных и работать с ней с помощью LINQ to SQL. В качестве базы данных, введённой в Windows Phone Mange, выступает SQL Compact Edition. Так же как и Isolated Storage Settings, файл с базой данных лежит в корне Isolated Storage File. Для того, чтобы использовать реляционную базу, необходимо установить Windows Phone 7.1 Mango Developers Tools.

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

Начнём с малого, с настроек приложения. Что обычно можно хранить в этом случае? Например, пользователь может активировать, либо деактивировать настройку, которая позволяет приложению использовать его местоположение или нет. Ещё, если приложение использует какую-нибудь социальную сеть, скажем Facebook, то при логине мы получаем access_token, который иногда нужно хранить в течение всего цикла жизни нашего приложения, а может и дальше, для последующих запусков.

Итак, как я уже говорил, информация хранится в виде пары ключ-значение. Доступ к коллекции пар осуществляется через статический класс IsolatedStorageSettings, у которого есть свойство ApplicationSettings. Доступ к значению по ключу осуществляется как по индексу массива, в качестве индекса выступает строковое значение.

Сохраняем:

 

IsolatedStorageSettings.ApplicationSettings["IsLocationServicesEnabled"] = true;
IsolatedStorageSettings.ApplicationSettings["AccessToken"] = "XXXXXxxxxxxxxxXXXXXXXXXXXxxxxxxxxxx";

Достаём:

 

if (IsolatedStorageSettings.ApplicationSettings.Contains("IsLocationServicesEnabled"))
{
var isLocationServicesEnabled = (bool)IsolatedStorageSettings.ApplicationSettings["IsLocationServicesEnabled"];
}
if (IsolatedStorageSettings.ApplicationSettings.Contains("AccessToken "))
{
var accessToken = IsolatedStorageSettings.ApplicationSettings["AccessToken"] as string;
}

Как видите, перед тем, как прочитать данные, мы сначала проверяем, содержится ли такое значение в настройках по этому ключу. Это избавляет нас от NullReferenceException и от прочих неприятностей.

Чтобы удалить настройку, необходимо вызвать метод Remove и в качестве параметра передать ему ключ.


if (IsolatedStorageSettings.ApplicationSettings.Contains("IsLocationServicesEnabled"))
{
IsolatedStorageSettings.ApplicationSettings.Remove("IsLocationServicesEnabled");
}

Теперь перейдём к рассмотрению IsolatedStorageFile. Работа с локальной файловой системой нисколько не отличается от работы с файловой системой компьютера средствами .NET, т.ч. если вы освоили StreamReader, StreamWriter и другие объекты, которые позволяют работать с файлами, то считайте, что дело в шляпе. Создать папку можно следующим образом:


using(var storage = IsolatedStorageFile.GetUserStoreForApplication())
{
var dirName = "new dir";
if (!storage.DirectoryExists("new dir"))
{
storage.CreateDirectory("new dir");
}
}

Объект storage представляет собой непосредственно само изолированное хранилище. Его мы получили через статический класс storage, используя метод GetUserStoreForApplication(). Далее мы проверили на существование такой папки, и если таковой не нашлось, то мы её создаём.

Теперь запишем в эту директорию некий файл. Модернизируем наш код следующим образом:


using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
{
const string dirName = "new dir";
if (!storage.DirectoryExists("new dir"))
{
storage.CreateDirectory("new dir");
}
using (var isoFileStream = new IsolatedStorageFileStream(string.Concat(dirName, "\myFile.txt"), FileMode.OpenOrCreate, storage))
{
using (var isoFileWriter = new StreamWriter(isoFileStream))
{
isoFileWriter.WriteLine("some text");
}
}
}

Мы создали объект типа IsolatedStorageFileStream, и указали ему, что хотим открыть файл myFile.txt, который находится в папке “new dir” (как вы могли заметить, разделителем является двойной обратный слэш). Второй параметр означает, что если такого файла не существует, то мы его создадим. Третий параметр указывает на то, что работа с папкой и файлом происходит в контексте нашего локального хранилища для приложения.

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

Создадим интерфейс, который будет определять, какие операции сможет предоставить наш сервис.


public interface IFileManager
{
byte[] Get(string key);
bool ContainsData { get; }
void Insert(string key, byte[] buffer);
void Delete(string key);
void Clear();
}

Реализуем наш интерфейс. Я приведу полный пример кода и постараюсь дать комментарии к каждому из методов нашего класса:


public class FileManager : IFileManager
{
// именно так называется файл с настройками, о чём было сказано выше.
private const string ApplicationSettingsFileName = "__ApplicationSettings";

// создаём пустой массив байт, проверяем наличие такого файла в нашем хранилище. Если такого файла нет, то возвращаем пустой буфер, иначе используя метод OpenFile объекта IsolatedStorageFile открываем IsolatedStorageFileStream и читаем из него информацию в наш массив.
public byte[] Get(string key)
{
var buffer = new byte[]{};

using(var storage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!storage.FileExists(key))
{
return buffer;
}
using(var stream = storage.OpenFile(key, FileMode.Open, FileAccess.Read))
{
buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
}
}
return buffer;
}
// Проверяем наличие файла в хранилище. Если такой имеется, то мы удаляем его и создаём новый файл, в который пишем входной массив через метод Write объекта IsolatedStorageFileStream.
public void Insert(string key, byte[] buffer)
{
using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (storage.FileExists(key))
{
storage.DeleteFile(key);
}
using (var stream = storage.OpenFile(key, FileMode.Create, FileAccess.Write))
{
stream.Write(buffer, 0, buffer.Length);
}
}
}
// Проверяем наличие файла, и если таковой имеется, то удаляем его.
public void Delete(string key)
{
using (var isolatedFile = IsolatedStorageFile.GetUserStoreForApplication())
{
if (isolatedFile.FileExists(key))
{
isolatedFile.DeleteFile(key);
}
}
}
// Данное свойство говорит нам о том, имеются ли какие-то данные в нашем хранилище. Здесь есть маленький нюанс. Как вы помните, IsolatedStorageSettings хранятся в корне нашего хранилища. Следовательно мы должны учесть тот факт, что если этот файл там единственный, то хранилище пустое, иначе там есть информация. Делается это следующим образом:
public bool ContainsData
{
get
{
using (var iso = IsolatedStorageFile.GetUserStoreForApplication())
{
var fileNames = iso.GetFileNames();
var directoryNames = iso.GetDirectoryNames();
if (directoryNames.Length == 0 && fileNames.Length == 1 && fileNames[0] == ApplicationSettingsFileName)
{
return false;
}
return fileNames.Length > 0 || directoryNames.Length > 0;
}
}
}
// Этот метод форматирует нашу файловую систему. Наверное, вы наверняка задались вопросом: а как быть с настройками приложения, которые, судя по всему, также удалятся вместе с остальной информацией? Спешу вас успокоить, что настройки в течение цикла жизни приложения хранятся в рабочей памяти приложения, но после того, как приложение закрывается (нормальным путём, а не непредвиденными ошибками и исключительными ситуациями), данные настройки автоматически сохраняются в хранилище.
public void Clear()
{
using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
{
storage.Remove();
}
}
}

Ну вот и всё. Теперь мы умеем работать с файловой системой, а это значительно упрощает нам жизнь, ведь очень часто приложение может хранить какие-то данные.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *