Xamarin.Forms でのファイル処理

Xamarin.Forms でのファイル処理は、.NET Standard ライブラリ内のコードを使用するか、埋め込みリソースを使用することで実現できます。

概要

Xamarin.Forms コードは複数のプラットフォーム上で実行され、各プラットフォームには独自のファイルシステムがあります。 そのことは以前、各プラットフォームでネイティブ ファイル API を使用することが最も簡単なファイルの読み書き方法であったことを意味しました。 代替的に、アプリでデータ ファイルを配布する方法として埋め込みリソースが最も単純な解決策となります。 ただし、.NET Standard 2.0 の場合、.NET Standard ライブラリでファイル アクセス コードを共有できます。

イメージ ファイルの処理方法については、イメージの使用に関するページを参照してください。

ファイルの保存と読み込み

System.IO クラスを使用し、各プラットフォームのファイル システムにアクセスできます。 File クラスでは、ファイルを作成し、削除し、読み込むことができます。Directory クラスでは、ディレクトリの内容を作成し、削除し、列挙できます。 Stream サブクラスを使用することもできます。このサブクラスは、ファイル操作をより詳細に制御できます (圧縮やファイル内の位置検索など)。

テキスト ファイルは File.WriteAllText メソッドを利用して書き込むことができます。

File.WriteAllText(fileName, text);

テキスト ファイルは File.ReadAllText メソッドを利用して読み込むことができます。

string text = File.ReadAllText(fileName);

また、File.Exists メソッドでは、指定のファイルが存在するかどうかが判断されます。

bool doesExist = File.Exists(fileName);

各プラットフォームのファイル パスは、Environment.GetFolderPath メソッドの最初の引数として Environment.SpecialFolder 列挙の値を使用することで、.NET Standard ライブラリから特定できます。 これを次に、Path.Combine メソッドでファイル名と組み合わせることができます。

string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "temp.txt");

このような操作はサンプル アプリでデモとして示されています。これには、テキストを保存し、読み込むページが含まれています。

テキストの保存と読み込み

リソースとして埋め込まれたファイルを読み込む

.NET Standard アセンブリにファイルを埋め込むには、ファイルを作成するか追加し、[ビルド アクション] が [EmbeddedResource] になっていることを確認します。

GetManifestResourceStream は、そのリソース ID を使用して埋め込みファイルにアクセスするために使用されます。 既定では、リソース ID は、リソースの埋め込み先のプロジェクトの既定の名前空間がプレフィックスとして付いたファイル名となります。この例では、アセンブリが WorkingWithFiles で、ファイル名が LibTextResource.txt であるため、リソース ID は WorkingWithFiles.LibTextResource.txt となります。

var assembly = IntrospectionExtensions.GetTypeInfo(typeof(LoadResourceText)).Assembly;
Stream stream = assembly.GetManifestResourceStream("WorkingWithFiles.LibTextResource.txt");
string text = "";
using (var reader = new System.IO.StreamReader (stream))
{  
    text = reader.ReadToEnd ();
}

それから text 変数を利用してテキストを表示するか、利用しない場合、コードで使用します。 次のスクリーンショットは、Label コントロールにレンダリングされたテキストを示しています。

.NET 標準ライブラリに埋め込まれたテキスト ファイル

XML の読み込みと逆シリアル化は同じくらい簡単です。 次のコードは、リソースから読み込まれ、逆シリアル化され、表示のために ListView にバインドされる XML ファイルを示します。 この XML ファイルには Monkey オブジェクトの配列が含まれています (クラスはサンプル コードで定義されています)。

var assembly = IntrospectionExtensions.GetTypeInfo(typeof(LoadResourceText)).Assembly;
Stream stream = assembly.GetManifestResourceStream("WorkingWithFiles.LibXmlResource.xml");
List<Monkey> monkeys;
using (var reader = new System.IO.StreamReader (stream)) {
    var serializer = new XmlSerializer(typeof(List<Monkey>));
    monkeys = (List<Monkey>)serializer.Deserialize(reader);
}
var listView = new ListView ();
listView.ItemsSource = monkeys;

ListView に表示された .NET 標準ライブラリに埋め込まれた Xml ファイル

共有プロジェクトに埋め込む

共有プロジェクトにも埋め込みリソースとしてファイルを含めることができます。ただし、共有プロジェクトの内容は参照元プロジェクトにコンパイルされるため、埋め込みファイル リソース ID に使用されるプレフィックスは変わることがあります。 つまり、埋め込みファイルごとのリソース ID はプラットフォームによって異なる場合があります。

共有プロジェクトのこの問題には 2 つの解決策があります。

  • プロジェクトを同期する - 各プラットフォームのプロジェクト プロパティを編集し、同じアセンブリ名と既定の名前空間を使用します。 この値は共有プロジェクトの埋め込みリソース ID のプレフィックスとして "ハードコード" できます。
  • #if コンパイラ ディレクティブ - コンパイラ ディレクティブを使用して正しいリソース ID プレフィックスを設定し、その値を使用して正しいリソース ID を動的に構築します。

2 つ目のオプションを示すコードを以下に示します。 コンパイラ ディレクティブを使用し、ハードコードされたリソース プレフィックス (通常、参照元プロジェクトの既定の名前空間と同じです) を選択します。 次に、resourcePrefix 変数を埋め込みリソース ファイル名と連結することで有効なリソース ID が作成されます。

#if __IOS__
var resourcePrefix = "WorkingWithFiles.iOS.";
#endif
#if __ANDROID__
var resourcePrefix = "WorkingWithFiles.Droid.";
#endif

Debug.WriteLine("Using this resource prefix: " + resourcePrefix);
// note that the prefix includes the trailing period '.' that is required
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(SharedPage)).Assembly;
Stream stream = assembly.GetManifestResourceStream
    (resourcePrefix + "SharedTextResource.txt");

リソースを整理する

上の例では、.NET Standard ライブラリ プロジェクトのルートにファイルが埋め込まれるものと想定されています。その場合、リソース ID の形式は Namespace.Filename.Extension で、WorkingWithFiles.LibTextResource.txtWorkingWithFiles.iOS.SharedTextResource.txt のようになります。

埋め込みリソースはフォルダーで整理できます。 埋め込みリソースをフォルダーに入れると、フォルダー名がリソース ID の一部になります (ピリオドで区切られます)。そのため、リソース ID の形式は Namespace.Folder.Filename.Extension になります。 サンプル アプリで使用するファイルをフォルダー MyFolder に入れると、対応するリソース ID が WorkingWithFiles.MyFolder.LibTextResource.txtWorkingWithFiles.iOS.MyFolder.SharedTextResource.txt になります。

埋め込みリソースのデバッグ

特定のリソースが読み込まれない理由がわからない場合があるため、リソースが正しく構成されていることを確認する目的で、次のデバッグ コードをアプリケーションに一時的に追加できます。 所与のアセンブリに埋め込まれている既知のリソースがすべて [エラー] パッドに出力されるので、リソース読み込み問題のデバッグに役立ちます。

using System.Reflection;
// ...
// use for debugging, not in released app code!
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(SharedPage)).Assembly;
foreach (var res in assembly.GetManifestResourceNames()) {
    System.Diagnostics.Debug.WriteLine("found resource: " + res);
}

まとめ

この記事では、デバイスでテキストを保存し、読み込むことや埋め込みリソースを読み込むことなど、簡単なファイル操作をいくつか確認しました。 .NET Standard 2.0 の場合、.NET Standard ライブラリでファイル アクセス コードを共有できます。