SIN@SAPPOROWORKSの覚書

C#を中心に、夜な夜な試行錯誤したコードの記録です。

Xamarin.Forms PCLでのファイルIO ( PCL Storageを使用する )

【 Xamarin 記事一覧 】

1. PCL Storage

Xamarin.FormsのPCLでファイルのIOを書こうとしたとき、System.IOに File や Directory が無くて固まった経験はないでしょうか?
もともと、ファイルの扱いはプラットフォーム固有なので、当然といえば当然なのですが・・・

しかし、Xamarin.iOSやXamarni.Androidでは、ちゃんと、System.IO.FileやSystem.IO.Directoryが使えるので、それをラッパーすればいいだけです。
フォルダのパスがプラットフォーム固有になるので、そこだけ気を付ければいいって事でしょうか。


と言いながら、いろいろ検索していると、コンポーネントストアに「PCL Storage」なるものを見つけました。
f:id:furuya02:20150506131241p:plain:w350:left
f:id:furuya02:20150506131254p:plain:w350:left


2. インストール

同プログラムは、CodePlexGithubでコードも公開されています。
また、NuGetでのインストールも可能です。

f:id:furuya02:20150506131307p:plain:w350
コンソールでも可能ですが、今回は、「NnuGetパッケージの管理」から行いました。
※実は、ComponentsというフォルダがiOSAndroidのプロジェクトにしかなく、PCLプロジェクトが無かったので、右クリックでの導入要領が分かりませんでした・・・

f:id:furuya02:20150506131324p:plain
全プロジェクトにインストールされます。
f:id:furuya02:20150506131331p:plain

3. 動作確認

次のようなサンプルを書いて、動作確認してみました。
EntryコントロールとButtonコントロールを配置し、ボタンを押すと、Entryコントロールの内容をファイルに書き込むものです。

//App.cs
using PCLStorage;
using Xamarin.Forms;
namespace PCLStorageSample {
    public class App : Application {
        public App() {
            MainPage = new MyPage();
        }
    }

    internal class MyPage : ContentPage {
        public MyPage() {
            var entry = new Entry();
            var button = new Button() {
                Text = "OK",
                Command = new Command(async () => {
                    // ルートフォルダの取得
                    var folder = FileSystem.Current.LocalStorage;

                    // フォルダの作成
                    var subFolder = await folder.CreateFolderAsync("SubFolder", CreationCollisionOption.OpenIfExists);

                    // フォルダの作成
                    var file = await subFolder.CreateFileAsync("Text.txt", CreationCollisionOption.ReplaceExisting);

                    // Entryコントロール尾内容をの書き込む
                    await file.WriteAllTextAsync(entry.Text);
                    
                    // ファイルの内容を読み込む
                    var str = await file.ReadAllTextAsync();
                    str = "";
                })
            };
            Content = new StackLayout{
                Padding = new Thickness(0,Device.OnPlatform(20,0,0),0,0),
                Children = {
                    entry,button
                }
            };
        }
    }
}

(1) iOS

上記のコードを実行すると、下記のような画面になります。
f:id:furuya02:20150506131342p:plain:w200
Entryコントロールに「test-message」と入力して、OKボタンを押し、ファイルのIOを行ったところでブレークポイントで止めて、内容を確認してみました。
f:id:furuya02:20150506131351p:plain
ファイルから読み込んだ内容が、書き込んだものと同じになっているのが、確認できます。
また、この時の、各オブジェクトの状況は次のようになっています。
f:id:furuya02:20150506131356p:plain
PCLStorage.IFolder folder のパスは、「/User/username/Library/developer/CoreSimulator/Data/Application/A3297...C370/Document/..Library」となっており、そのサブフォルダ「SubFolder」とその中の
ファイル「Text.txt」が見て取れます。

※これは、シュミレータでの動作ですが、実機では「/var/mobile/Containers/Data/Application/53B38A17-AC94-49C9-A3E7-21A2B08F5706/Documents/../Library」のようになっています。

(2) Android

Androidでは、次のようになります。
f:id:furuya02:20150506131402p:plain:w200
Entryコントロールに「test-android」と入力して、iOSと同じ要領で確認してみました。
f:id:furuya02:20150506131410p:plain

今度は、PCLStorage.IFolder folder のパスが「/data/data/PCLStorageSample.Droid/files」となっているのが確認できます。

(3) WindowsPhone

最後に、WindowsPhoneです。
f:id:furuya02:20150506131435p:plain:w200
こちらの、PCLStorage.IFolder folder は、「/data/data/PCLStorageSample.Droid/files」です。
f:id:furuya02:20150506131420p:plain

4. ルートフォルダ

念のため、各プラットフォームごとのルートフォルダの取得について、Githubからコードを確認しておきます。
https://github.com/dsplaisted/PCLStorage/blob/master/src/PCLStorage.FileSystem.Desktop/DesktopFileSystem.cs

public IFolder LocalStorage{
            get{
                //  SpecialFolder.LocalApplicationData is not app-specific, so use the Windows Forms API to get the app data path
                //var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
#if ANDROID
                var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
#elif IOS
                var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
                var localAppData = Path.Combine(documents, "..", "Library");
#else
                var localAppData = System.Windows.Forms.Application.LocalUserAppDataPath;
#endif
                return new FileSystemFolder(localAppData);
            }
        }

コードを確認すると、AndroidiOS、WindowsPhoneについては、ルートフォルダの取得以外やパスの扱いいがは、ほとんど共通のようです。
しかし、何と言っても、パッケージインストールだけで簡単に使えてしまう魅力は捨てがたいです。




【 Xamarin 記事一覧 】