Доступ к файловой системе из Portable Class Library (PCL)

В один прекрасный день у меня появилась идея о портировании своего .NET кода на другие платформы с вынесением основной логики (все что не касается UI) в отдельную библиотеку Portable Class Library (PCL).

В теории звучит все классно – с PCL можно работать практически на всех устройствах, и не только с .NET Framework, но и даже с Mono! С таком подходом открываются большие мультиплатформенные перспективы, к примеру, перенос кода Windows Phone на Android и iOS с помощью Xamarin.





Но ознакомившись с PCL поближе, я пришел к выводу, что такая библиотека это по сути урезанный .NET, учитывающий ограничения каждой платформы. То есть даже на с виду похожих WP8 и W8 не удастся все спихнуть в PCL.



Таблица возможностей PCL на разных платформах


На первый взгляд мой код должен был перейти без проблем (целевые платформы: Windows .NET, Windows 8, Windows Phone), но компилятор обругал System.IO, а именно StreamReader, который напрямую открывал файл.

Вспомнив что у Windows 8 и Windows Phone совершенно другие способы для работы с файлами и разные между собой:

WP использует IsolatedStorage для доступа к файлам приложения, а Windows 8, хоть и имеет доступ к публичным папкам, но делает это через Windows.Storage (WP8 тоже теперь может через него, но для сохранения поддержки WP7 такой способ не рекомендуется использовать). Попользовавшись гуглом, мне стало ясно, что организовать доступ к файлам на чистом PCL невозможно, а советы вроде передачи Steam уже из приложения или жесткого включения файла в DLL для моего решения не подходили. Дело в том, что программа работала с большим внешним словарем и сохраняла временные результаты работы в файлах. Но тут на глаза попалась библиотека PCLStorage, обещавшая какую-никакую работу с ФС через PCL.

PCLStorage предоставляет три интерфейса – IFIle, IDirectory, IFileSystem, все они обеспечивают асинхронные операции чтения и записи файлов и директорий.

Примечание: Все дальнейшие тесты проводились на «классическом» Windows.

Пример записи файла:

 public async Task PCLCreateFile(string name, string content)
        {
            IFolder localStorage = FileSystem.Current.LocalStorage;
      
            IFolder contentFolder = await localStorage.CreateFolderAsync("Content", CreationCollisionOption.OpenIfExists);

            IFile file = await contentFolder.CreateFileAsync(name, CreationCollisionOption.ReplaceExisting);

            await file.WriteAllTextAsync(content);
        }


Пример чтения файла:

      public async Task<string> PCLReadFile(string name)
        {
            IFolder localStorage = FileSystem.Current.LocalStorage;

            IFolder contentFolder = await localStorage.GetFolderAsync("Content");

            IFile file = await contentFolder.GetFileAsync(name);

            return await file.ReadAllTextAsync();
        }


Выглядит и работает все отлично. Но… как получить доступ к файлу, который находится в директории программы?

IFileSystem возвращает два пути LocalStorage и RoamingStorage. Первый указывает на директорию которая выделена для программы в текущей системе, второй на публичную директорию для синхронизации данных. В частности в Windows LocalStorage указывал на (AppData\Local), что далеко не являлось директорией приложения и не содержало никаких файлов.

На директорию приложения PCLStorage, к сожалению, указать не могло.

Конечно, возможно было создать специальный инсталлятор, но как быть в случае Store приложений? Тем не менее, решение появилось – копирование файлов в LocalStorage из самого приложения (или загрузка из сети в самом PCL (не проверялось)). Что же, способ в итоге вышел более простой, чем передача Stream, плюс появилась возможность работать со временными файлами в ограниченной среде портативной библиотеки.

P.S.: Под конец эксперимента оказалось что поддержку WP7 из последней версии выкинули, из-за чего собственно говоря все и затевалось (Из-за раздельного использования IsolatedStorage на WP и Windows.Storage на Windows 8).
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 5

    +2
    >>Но ознакомившись с PCL поближе, я пришел к выводу, что такая библиотека это по сути урезанный .NET, учитывающий ограничения каждой платформы.
    Логично, нет? Как-то так и не понял посыл этой статьи.
      +1
      Мы пользуемся уже готовыми плагинами MvvmCross
      github.com/MvvmCross/MvvmCross/wiki/MvvmCross-plugins

      The File plugin provides cross-platform access to a File Store API:

      public interface IMvxFileStore
      {
      bool TryReadTextFile(string path, out string contents);
      bool TryReadBinaryFile(string path, out Byte[] contents);
      bool TryReadBinaryFile(string path, Func<Stream, bool> readMethod);
      void WriteFile(string path, string contents);
      void WriteFile(string path, IEnumerable contents);
      void WriteFile(string path, Action writeMethod);
      bool TryMove(string from, string to, bool deleteExistingTo);
      bool Exists(string path);
      bool FolderExists(string folderPath);
      string PathCombine(string items0, string items1);
      string NativePath(string path);

      void EnsureFolderExists(string folderPath);
      IEnumerable GetFilesIn(string folderPath);
      void DeleteFile(string path);
      void DeleteFolder(string folderPath, bool recursive);
      }
      • UFO just landed and posted this here
          0
          PCL был только ради эксперимента. А что насчет Stream, то тут расходовалось слишком много ОЗУ, что не подходило для WP
          0

          Only users with full accounts can post comments. Log in, please.