Windowsフォーム開発者のためのWindows 10 UWPアプリ開発入門(後編):特集:UWPとは何か(4/5 ページ)
本稿ではデータバインド/非同期処理/ファイル操作/クラウド型アーキテクチャという、Windowsフォームとは異なるUWPプログラミングの特徴を取り上げる。
5. ファイルの読み書き〜セキュリティ優先設計
UWPアプリの開発を始めると、「なぜこんなに不便なんだろう!?」ときっと思うはずだ。ここではファイルアクセスについて取り上げるが、その他にも印刷プレビューを出さないと印刷できないとか、他のプロセスと自由に通信できないといった、(Windowsフォームでの開発から見ると)さまざまな制約がある。
UWPは、その前身であるWindowsストアアプリ(開発時コードネーム「Metroスタイルアプリ」)の最初から、エンドユーザーが信頼できるプラットフォームであることを目標の一つにしている(例えば「Building Windows 8:信頼できる Metro スタイル アプリを提供する」を参照)。そのため上に述べたようなさまざまな制約が課せられているのである。UWPアプリでは、エンドユーザーのプライバシーやセキュリティを優先する設計を考えねばならない。
例として、フォルダーの中のファイルを一覧するコードをWindowsフォームとUWPアプリとで紹介しよう。
Windowsフォームでのファイル一覧
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();
フォームには「listBox1」という名前のListBoxコントロールを配置しておく。
ここではAPIを使ってフォルダーのフルパスを取得したが、実行中の権限でアクセスできるフォルダーであれば、任意のフォルダーのファイルを同様にして取り出せる。
UWPアプリで「ピクチャ」フォルダーにアクセスする
UWPアプリでのファイルアクセスはかなり制限されている。自由に読み書きできるのは、アプリごとに与えられた「アプリケーションデータ記憶域」と呼ばれる領域のみだ。その他に、「ピクチャ」フォルダーなどのいくつかのフォルダーは、マニフェストに宣言することでアクセスできるようになる。それ以外の任意のフォルダーにアクセスするには、ファイルピッカーやフォルダーピッカーなどを利用してエンドユーザーに選択してもらわねばならない。
まず、「ピクチャ」フォルダーのファイル一覧を取得する方法を紹介しよう(別途公開のサンプルでは、「S4_FileIO」ディレクトリの下にある「S4_02_Uwp」プロジェクト)。最初に、マニフェストでそのことを宣言しなければならない(宣言していないと実行時に例外になる)。ソリューションエクスプローラーで「Package.appxmanifest」ファイルをダブルクリックして、マニフェストエディターを開く(次の画像)。そうしたら、[機能]タブを選び、そこで[ピクチャ ライブラリ]にチェックを付ける。
マニフェストエディターで「ピクチャ」フォルダーにアクセスできるようにする
ソリューションエクスプローラーで「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);
}
ページにはListBoxコントロールを配置し、そのItemsSourceプロパティとこのコードにある「_fileNames」メンバー変数をバインドしておく。また、Buttonコントロールを配置し、そのクリックイベントのハンドラーとして「button1_Click」メソッドを指定しておく。
得られたフォルダーやファイルは文字列ではなく、Windows.Storage名前空間のStorageFolderオブジェクト/StorageFileオブジェクトであることに注意。これらのオブジェクトを直接作ることはできない(コンストラクターがprivateになっている)。また、ファイルやフォルダーのパス文字列を与えて作ることもできない。ただし、取得したStorageFolderオブジェクト/StorageFileオブジェクトからパス文字列を得ることはできる。
また、ファイルの一覧を取得するところにawaitキーワードが登場しており、メソッドのシグネチャにはasyncキーワードが追加してあることにも注意してほしい。前述したように、ファイルアクセスのAPIには非同期処理のものが多いのである。
UWPアプリで任意のフォルダーにアクセスする
次に、任意のフォルダーにアクセスするためエンドユーザーに選択してもらう方法を紹介しよう(別途公開のサンプルでは、同じく「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);
}
ページにはListBoxコントロールを配置し、そのItemsSourceプロパティとこのコードにある「_fileNames」メンバー変数をバインドしておく。また、Buttonコントロールを配置し、そのクリックイベントのハンドラーとして「button2_Click」メソッドを指定しておく。
このコードを実行してみると次の画像のようになる。UWPアプリでローカルリソースにアクセスするには、このようにエンドユーザーの操作が要求されるかマニフェストでの宣言が必要なると覚えておいてほしい。
フォルダーを選択して[フォルダーの選択]ボタンをクリック(赤丸内)
【コラム】 ファイルアクセスについてさらに詳しく!
UWPアプリでのファイルアクセスについては、次の記事をご覧いただきたい。Windows 8.1時代の記事であるが、Windows 10のUWPアプリでも基本は同じだ。
なお、エンドユーザーに選択してもらったファイル/フォルダーは、次からはコードから直接開くことも可能である。次の記事を参照してほしい。
Copyright© Digital Advantage Corp. All Rights Reserved.