UWPアプリの開発を始めると、「なぜこんなに不便なんだろう!?」ときっと思うはずだ。ここではファイルアクセスについて取り上げるが、その他にも印刷プレビューを出さないと印刷できないとか、他のプロセスと自由に通信できないといった、(Windowsフォームでの開発から見ると)さまざまな制約がある。
UWPは、その前身であるWindowsストアアプリ(開発時コードネーム「Metroスタイルアプリ」)の最初から、エンドユーザーが信頼できるプラットフォームであることを目標の一つにしている(例えば「Building Windows 8:信頼できる Metro スタイル アプリを提供する」を参照)。そのため上に述べたようなさまざまな制約が課せられているのである。UWPアプリでは、エンドユーザーのプライバシーやセキュリティを優先する設計を考えねばならない。
例として、フォルダーの中のファイルを一覧するコードをWindowsフォームとUWPアプリとで紹介しよう。
Windowsフォームでは(というよりも従来のデスクトップ用プログラムでは)、実行時にプログラムに与えられている権限でアクセス可能な範疇であれば、任意のフォルダーやファイルにアクセスできる。
例えば、ユーザーの「ピクチャ」フォルダーに格納されているファイルの一覧を取得してリストボックスに表示するコードは、次のように書ける(別途公開のサンプルでは、「S4_FileIO」ディレクトリの下にある「S4_01_WinForm」プロジェクト)。
// 「ピクチャ」フォルダー(フルパス)
string folder
= Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
// ファイル(フルパス)の一覧を取得する
IEnumerable<string> files
= System.IO.Directory.EnumerateFiles(folder);
// 一覧のフルパスからファイル名だけを取り出して、リストボックスに表示する
listBox1.DataSource
= files.Select(p => System.IO.Path.GetFileName(p)).ToList();
UWPアプリでのファイルアクセスはかなり制限されている。自由に読み書きできるのは、アプリごとに与えられた「アプリケーションデータ記憶域」と呼ばれる領域のみだ。その他に、「ピクチャ」フォルダーなどのいくつかのフォルダーは、マニフェストに宣言することでアクセスできるようになる。それ以外の任意のフォルダーにアクセスするには、ファイルピッカーやフォルダーピッカーなどを利用してエンドユーザーに選択してもらわねばならない。
まず、「ピクチャ」フォルダーのファイル一覧を取得する方法を紹介しよう(別途公開のサンプルでは、「S4_FileIO」ディレクトリの下にある「S4_02_Uwp」プロジェクト)。最初に、マニフェストでそのことを宣言しなければならない(宣言していないと実行時に例外になる)。ソリューションエクスプローラーで「Package.appxmanifest」ファイルをダブルクリックして、マニフェストエディターを開く(次の画像)。そうしたら、[機能]タブを選び、そこで[ピクチャ ライブラリ]にチェックを付ける。
このようにして[機能]タブで設定した機能がアプリから利用できるようになるが、Windowsストアではアプリの追加情報欄にその機能が表示される。エンドユーザーがそのアプリをインストールするかどうかの判断材料に使われるのである。従って、一見するとアプリとは関係なさそうに思えるような機能を使うときは、その理由をアプリの説明に書いておくのがよいだろう。
そうしたら、次のようなコードを書く。ここではボタンのクリックイベントハンドラーに記述した。
// 画面にバインドするメンバー変数
System.Collections.ObjectModel.ObservableCollection<string>
_fileNames
= new System.Collections.ObjectModel.ObservableCollection<string>();
private async void button1_Click(object sender, RoutedEventArgs e)
{
// 「ピクチャ」フォルダー
Windows.Storage.StorageFolder folder
= Windows.Storage.KnownFolders.PicturesLibrary;
// ファイルの一覧を取得する
IReadOnlyList<Windows.Storage.StorageFile> files
= await folder.GetFilesAsync();
// 一覧からファイル名だけを取り出して、データを更新する
IEnumerable<string> fileNames = files.Select(sf => sf.Name);
_fileNames.Clear();
foreach (string fileName in fileNames)
_fileNames.Add(fileName);
}
次に、任意のフォルダーにアクセスするためエンドユーザーに選択してもらう方法を紹介しよう(別途公開のサンプルでは、同じく「S4_FileIO」ディレクトリの下にある「S4_02_Uwp」プロジェクト)。それには、Windows.Storage.Pickers名前空間のFolderPickerクラスを使う。
FolderPickerクラスを使うときには、マニフェストでの宣言は要らない。従って、次のようなコードを書くだけでよい。ここではボタンのクリックイベントハンドラーに記述した。
// 画面にバインドするメンバー変数
System.Collections.ObjectModel.ObservableCollection<string>
_fileNames
= new System.Collections.ObjectModel.ObservableCollection<string>();
private async void button2_Click(object sender, RoutedEventArgs e)
{
// フォルダーピッカーを出して、エンドユーザーにフォルダーを選択してもらう
var picker = new Windows.Storage.Pickers.FolderPicker();
picker.FileTypeFilter.Add("*"); //拡張子の指定は必須
Windows.Storage.StorageFolder folder
= await picker.PickSingleFolderAsync();
// エンドユーザーがフォルダーを選択しなかったときはnullが返る
if (folder == null)
return;
// 以下は先ほどのコードと同じ
// ファイルの一覧を取得する
IReadOnlyList<Windows.Storage.StorageFile> files = await folder.GetFilesAsync();
// 一覧からファイル名だけを取り出して、リストボックスに表示する
IEnumerable<string> fileNames = files.Select(sf => sf.Name);
_fileNames.Clear();
foreach (string fileName in fileNames)
_fileNames.Add(fileName);
}
このコードを実行してみると次の画像のようになる。UWPアプリでローカルリソースにアクセスするには、このようにエンドユーザーの操作が要求されるかマニフェストでの宣言が必要なると覚えておいてほしい。
UWPアプリでのファイルアクセスについては、次の記事をご覧いただきたい。Windows 8.1時代の記事であるが、Windows 10のUWPアプリでも基本は同じだ。
なお、エンドユーザーに選択してもらったファイル/フォルダーは、次からはコードから直接開くことも可能である。次の記事を参照してほしい。
Copyright© Digital Advantage Corp. All Rights Reserved.