連載
» 2013年06月27日 12時19分 UPDATE

WinRT/Metro TIPS:アプリケーション・データ記憶域のテキスト・ファイルを読み書きするには?[Win 8/WP 8]

アプリケーション・データ記憶域でファイルを作成/削除/コピーしたり列挙したりする方法、そしてテキスト・ファイルの内容を読み書きする方法を説明する。

[山本康彦,BluewaterSoft]
WinRT/Metro TIPS
業務アプリInsider/Insider.NET

powered by Insider.NET

「WinRT/Metro TIPS」のインデックス

連載目次

 アプリ・パッケージに同梱したテキスト・ファイルは、読み取れるけれども(「WinRT/Metro TIPS アプリに同梱したテキスト・ファイルを読むには?[Win 8/WP 8]」を参照)、書き込めない。インストール後に変更を必要としないファイルならよいが、アプリでユーザーが設定するオプションや、アプリの状態などを保存したいときに、ファイルを自由に扱えないのでは困ってしまう。Windowsストア・アプリでは、アプリごとに自由にファイルを扱える場所が用意されている。それが「アプリケーション・データ記憶域」だ。

 そこで本稿では、アプリケーション・データ記憶域でファイルを作成/削除/コピーしたり列挙したりする方法、そしてテキスト・ファイルの内容を読み書きする方法を説明する。本稿のサンプルは「Windows Store app samples:MetroTips #42(Windows 8版)」と「Windows Store app samples:MetroTips #42(WP 8版)」からダウンロードできる。

 なお、掲載しているコードは特記なき場合はWindowsストア・アプリとWindows Phone 8(以降、WP 8)アプリで共通である。

事前準備

 Windows 8(以降、Win 8)向けのWindowsストア・アプリを開発するには、Win 8とVisual Studio 2012(以降、VS 2012)が必要である。これらを準備するには、第1回のTIPSを参考にしてほしい。本稿では64bit版Win 8 ProとVS 2012 Express for Windows 8を使用している。

 WP 8向けのアプリを開発するには、SLAT対応CPUを搭載したPC上の64bit版Win 8 Pro以上Windows Phone SDK 8.0(無償)が必要となる。

アプリケーション・データ記憶域

 アプリケーション・データ記憶域は、アプリごとに割り当てられたローカル・ストレージ(=HDDなど)のフォルダであり、この領域にあるファイルにはアプリから自由にアクセスできる。ファイルを作成したりコピーしたり、あるいはフォルダ内のファイルを列挙したり、それらのファイルを読み書きしたりもできる。アプリケーション・データ記憶域は、アプリごとのユーザー設定や、アプリの動作に必要なデータなどを保存するといった用途が想定されている*1

 アプリケーション・データ記憶域には、次の表に示す3種類がある。いずれも、ApplicationDataクラス(Windows.Storage名前空間)を利用してアクセスする。これら3つのプロパティはいずれもStorageFolderクラス(Windows.Storage名前空間)のオブジェクトだ。

名称 ApplicationDataオブジェクトのプロパティ URI Win 8 WP 8 ローカルとの相違点
ローカル LocalFolder ms-appdata:///local/ ---
ローミング RoamingFolder ms-appdata:///roaming/ ×*2 ユーザーの保有する他のデバイスと自動的に同期される*3
一時 TemporaryFolder ms-appdata:///temporary/ ×*2 システムによって削除されることがある
アプリケーション・データ記憶域の種類

 本稿ではローカル・アプリケーション・データ記憶域(以降、ローカル・ストア)のファイルへのアクセス方法を説明するが、3つの記憶域(=上の表のプロパティ)でStorageFolderオブジェクトの取得方法が異なる以外は、その使い方は同じである。

*1 アプリケーション・データ記憶域は、アプリがアンインストールされるときには消されてしまう。従って、アンインストール後もユーザーが必要とするデータを保管してはいけない。

*2 ローミングと一時データ記憶域は、WP 8ではAPIは存在するが実装されていない。

*3 同期されるとApplicationData.Current.DataChangedイベントが発生するので、ファイルを読み込み直す必要がある。また、同期される容量には制限がある。


本稿で作成するアプリの外観

 完成したアプリの外観と、XAMLコードを先に掲載しておこう。

完成したアプリの外観(Win 8)
完成したアプリの外観(WP 8) 完成したアプリの外観(上:Win 8、下:WP 8)

……省略……
<!-- ローカル・ストアの実際の場所 -->
<TextBlock x:Name="textLocalStorage" ……省略…… />
……省略……
<Button Tapped="createButton_Tapped" Content="test.txtファイルを作成" />
<Button Tapped="copyButton_Tapped" Content="アプリ同梱のファイルをコピー" />
<Button Tapped="listButton_Tapped" Content="ローカル・ストアのファイルを列挙" />
<Button Tapped="deleteButton_Tapped" Content="ローカル・ストアのファイルを削除" />
……省略……
<!-- ローカル・ストアのファイル一覧 -->
<ListBox x:Name="fileNameList"
         SelectionChanged="fileNameList_SelectionChanged" ……省略…… />

<!-- 読み取ったファイルの内容(編集可) -->
<TextBox x:Name="editTextBox" TextWrapping="Wrap" AcceptsReturn="True" ……省略…… />
<Button Tapped="overwriteButton_Tapped" Content="上書き保存" ……省略…… />
……省略……

完成したアプリのXAMLコード(XAML)
これはWin 8用のコードであり、WP 8ではButtonコントロールの「Tapped」イベントが「Click」イベントになる(このサンプルではイベント・ハンドラ名は「〜_Tapped」をそのまま利用する)。
また、レイアウトのためのGridコントロールやStackPanelコントロールは省略してある。

ローカル・ストアの実際の場所

 ローカル・ストアの実際の場所が分からないと、テストやデバッグのときに困ることもあるかもしれない。確かめておこう。

 まず、ローカル・ストアの場所を表示するためのTextBlockコントロールを画面の適当な場所に配置し、「textLocalStorage」と名前を付けておく。そうしたら、コードビハインドで次のコードのようにして、ローカル・ストアの実際の場所をApplicationDataオブジェクトから取得し、TextBlockコントロールに表示する。

this.textLocalStorage.Text
    = Windows.Storage.ApplicationData.Current.LocalFolder.Path;

Me.textLocalStorage.Text _
    = Windows.Storage.ApplicationData.Current.LocalFolder.Path

ローカル・ストアの実際の場所を取得して表示する(上:C#、下:VB)
このコードを記述する場所は、Win 8ではLoadStateメソッド(LayoutAwarePageクラスを継承した場合)またはOnNavigatedToメソッド(継承しない場合)、WP 8ではコンストラクタの末尾である。

 これで実行して表示されるのが、ローカル・ストアの実際の場所だ。例えば次のように表示されるだろう。

[Win 8の例]*4
D:\Users\biac\AppData\Local\Packages\140b61e0-1810-4335-83de-b77ce4350c76_88y8q2a7hew66\LocalState

[WP 8の例]
C:\Data\Users\DefApps\AppData\{1779174E-1ED5-473E-B5B7-3F951C6B37A8}\Local

 なお、パスの途中に長い識別子が入っているが、これはWindowsストア・アプリではパッケージ名*5、WP 8アプリではプロダクトID*6である。

*4 筆者の開発用PCは、DドライブにWindows 8をインストールしてあるため、このような場所になっている。通常はCドライブである。

*5 Windowsストア・アプリのパッケージ名は、Visual StudioでPackage.appxmanifestファイルをダブルクリックして開くと、その編集画面の[パッケージ化]タブに記載されている。なお、Windowsストアとアプリの関連付けを行うと、自動的に書き換えられる。

*6 WP 8アプリのプロダクトIDは、Visual StudioでPropertiesフォルダのWMAppManifest.xmlファイルをダブルクリックして開くと、その編集画面の[パッケージ化]タブに記載されている。


ローカル・ストアにファイルを作成するには?

 StorageFolderオブジェクトのCreateFileAsyncメソッドを使う。

 画面の適当な場所にButtonコントロールを配置し、そのTappedイベント・ハンドラ(WP 8ではClickイベント・ハンドラ)で、次のコードのように実装する。ApplicationDataオブジェクトからローカル・ストアを表すStorageFolderオブジェクトを取得したら、そのCreateFileAsyncメソッドを使ってファイルを作成する。

private async void createButton_Tapped(object sender, TappedRoutedEventArgs e)
{
  Windows.Storage.StorageFolder folder
    = Windows.Storage.ApplicationData.Current.LocalFolder;
  Windows.Storage.StorageFile newFile
    = await folder.CreateFileAsync("test.txt");
}

Private Async Sub createButton_Tapped(sender As Object, e As TappedRoutedEventArgs)
  Dim folder As Windows.Storage.StorageFolder _
      = Windows.Storage.ApplicationData.Current.LocalFolder
  Dim newFile As Windows.Storage.StorageFile _
      = Await folder.CreateFileAsync("test.txt")
End Sub

ローカル・ストアにファイルを作成するコード(上:C#、下:VB)
「test.txt」という名前で、空のファイル(ファイル・サイズが0byte)が作成される。すでに「test.txt」ファイルが存在するときは、例外が発生する。
このメソッドの第2引数はTappedRoutedEventArgsクラスになっているが、これはWin 8の場合。WP 8ではRoutedEventArgsクラスとなる。
また、awaitキーワード付きで非同期メソッドを呼び出しているので、async(C#)/Async(VB)キーワードでメソッドを修飾する必要もある(以下のコードでも同様)。

 上のコードでは、すでに同名のファイルが存在していると例外が発生する。そのようなときにどう処理するかを、第2引数にCreationCollisionOption列挙体(Windows.Storage名前空間)として指定できる。例えば、すでにファイルが存在していたときには、そのファイルを開くことにするなら、次のようになる。

private async void createButton_Tapped(object sender, TappedRoutedEventArgs e)
{
  Windows.Storage.StorageFolder folder
    = Windows.Storage.ApplicationData.Current.LocalFolder;
  Windows.Storage.StorageFile newFile
    = await folder.CreateFileAsync("test.txt",
            Windows.Storage.CreationCollisionOption.OpenIfExists);
}

Private Async Sub createButton_Tapped(sender As Object, e As TappedRoutedEventArgs)
  Dim folder As Windows.Storage.StorageFolder _
      = Windows.Storage.ApplicationData.Current.LocalFolder
  Dim newFile As Windows.Storage.StorageFile _
      = Await folder.CreateFileAsync("test.txt", _
              Windows.Storage.CreationCollisionOption.OpenIfExists)
End Sub

ローカル・ストアにファイルを作成するコード(改良版)(上:C#、下:VB)
すでに「test.txt」ファイルが存在したときは、先ほどのコードと違って、そのファイルを表すStorageFileオブジェクトが取得される。

 なお、このコードで実際にファイルが作成されたことを確認するには、後述する「ローカル・ストアのファイルを列挙するには?」のコードを使ってほしい。

ローカル・ストアにファイルをコピーするには?

 StorageFileオブジェクトのCopyAsyncメソッドを使う。

 よくあるアプリのパターンとして、インストールされてから最初の起動時に、アプリ同梱の設定ファイル(初期値が記述されているもの)をローカル・ストアにコピーすることがある。1回コピーした後は、アプリからそのローカル・ストアにある設定ファイルを読み書きするのだ。

 アプリ同梱のテキスト・ファイルをローカル・ストアにコピーしてみよう。

 まず、「WinRT/Metro TIPS アプリに同梱したテキスト・ファイルを読むには?[Win 8/WP 8]」と同様にして、プロジェクト内に「text」というフォルダを作り、そこに「sample01.txt」〜「sample03.txt」の3つのテキスト・ファイルを用意してほしい。

 次に、画面の適当な場所にButtonコントロールを配置し、そのTappedイベント・ハンドラ(WP 8ではClickイベント・ハンドラ)で、次のように、アプリ同梱のファイルをコピーするコードを実装する。コピー元とコピー先のStorageFolderオブジェクトを取得したら、GetFilesAsyncメソッドを使ってコピー元のフォルダにあるファイルを列挙し、得られたStorageFileオブジェクトのCopyAsyncメソッドを呼び出す。2つのStorageFolderオブジェクトを得る方法が、それぞれの場所によって異なることに注意してほしい。

private async void copyButton_Tapped(object sender, TappedRoutedEventArgs e)
{
  // アプリ・パッケージ内のtextフォルダを表すStorageFolderオブジェクト
  Windows.Storage.StorageFolder textFolder
      = await Windows.ApplicationModel.Package.Current
                .InstalledLocation.GetFolderAsync("text");

  // ローカル・ストア(=コピー先)を表すStorageFolderオブジェクト
  Windows.Storage.StorageFolder destFolder
    = Windows.Storage.ApplicationData.Current.LocalFolder;

  // textフォルダ内の全ファイルを列挙し、それぞれをローカル・ストアへコピーする
  foreach (Windows.Storage.StorageFile srcFile in await textFolder.GetFilesAsync())
  {
    Windows.Storage.StorageFile copiedFile = null;
    try
    {
      copiedFile = await srcFile.CopyAsync(destFolder);
    }
    catch { }
  }
}

Private Async Sub copyButton_Tapped(sender As Object, e As TappedRoutedEventArgs)
  ' アプリ・パッケージ内のtextフォルダを表すStorageFolderオブジェクト
  Dim textFolder As Windows.Storage.StorageFolder _
        = Await Windows.ApplicationModel.Package.Current _
                  .InstalledLocation.GetFolderAsync("text")

  ' ローカル・ストア(=コピー先)を表すStorageFolderオブジェクト
  Dim destFolder As Windows.Storage.StorageFolder _
      = Windows.Storage.ApplicationData.Current.LocalFolder

  ' textフォルダ内の全ファイルを列挙し、それぞれをローカル・ストアへコピーする
  For Each srcFile As Windows.Storage.StorageFile In Await textFolder.GetFilesAsync()
    Dim copiedFile As Windows.Storage.StorageFile = Nothing
    Try
      copiedFile = Await srcFile.CopyAsync(destFolder)
    Catch
    End Try
  Next
End Sub

アプリ同梱のテキスト・ファイルをローカル・ストアにコピーする(上:C#、下:VB)
このメソッドの第2引数はTappedRoutedEventArgsクラスになっているが、これはWin 8の場合。WP 8ではRoutedEventArgsクラスとなる。

 CopyAsyncメソッドで少々困ることは、実際のコピー中に何らかの原因で失敗したときと、すでに同名のファイルが存在していてコピーを実行できなかったときで、どちらの場合も同じSystem.Exception例外が発生するためにその区別がつかないことだ。例外が発生してもローカル・ストアでファイルを開いてみて、もしも開くことができたら、すでに同名のファイルが存在していたと判断できる(上のコードには実装していない)。あるいは、丁寧にやるならば、ローカル・ストアにファイルを作成して開き、アプリ・パッケージ内のファイルから読み込んだ内容を書き込むようにする。

ローカル・ストアのファイルを列挙するには?

 StorageFolderオブジェクトのGetFilesAsyncメソッドを使う。

 すでに先ほどのコードで、アプリ・パッケージ内のファイルを列挙しているが、今度はローカル・ストアにあるファイルを列挙して、そのファイル名を表示してみよう。

 画面の適当な場所にもう1つButtonコントロールを配置する。さらに、ListBoxコントロールも配置して「fileNameList」と名前を付けておく。そうしたら、そのButtonコントロールのTappedイベント・ハンドラ(WP 8ではClickイベント・ハンドラ)に次のコードを記述する。

private async void listButton_Tapped(object sender, TappedRoutedEventArgs e)
{
  await ListAllFilesAsync();
}

private async System.Threading.Tasks.Task ListAllFilesAsync()
{
  // ローカル・ストアを表すStorageFolderオブジェクト
  Windows.Storage.StorageFolder folder
    = Windows.Storage.ApplicationData.Current.LocalFolder;

  // フォルダ内の全ファイルを列挙し、ListBoxにバインドする
  this.fileNameList.ItemsSource = await folder.GetFilesAsync();
  // ListBoxには、与えたStorageFolderオブジェクトのNameプロパティを表示させる
  this.fileNameList.DisplayMemberPath = "Name";
}

Private Async Sub listButton_Tapped(sender As Object, e As TappedRoutedEventArgs)
  Await ListAllFilesAsync()
End Sub

Private Async Function ListAllFilesAsync() As System.Threading.Tasks.Task
  ' ローカル・ストアを表すStorageFolderオブジェクト
  Dim folder As Windows.Storage.StorageFolder _
      = Windows.Storage.ApplicationData.Current.LocalFolder

  ' フォルダ内の全ファイルを列挙し、ListBoxにバインドする
  Me.fileNameList.ItemsSource = Await folder.GetFilesAsync()
  ' ListBoxには、与えたStorageFolderオブジェクトのNameプロパティを表示させる
  Me.fileNameList.DisplayMemberPath = "Name"
End Function

ローカル・ストアのファイルを全部列挙して表示する(上:C#、下:VB)
イベント・ハンドラの第2引数はTappedRoutedEventArgsクラスになっているが、これはWin 8の場合。WP 8ではRoutedEventArgsクラスとなる。
なお、ListAllFilesAsyncメソッドとして切り出してあるのは、ほかのメソッドの中からも呼び出すためである。

 上のコードで、ファイル名をListBoxコントロールに表示する処理をListAllFilesAsyncメソッドとして独立させた。このメソッドの呼び出しを前述のcreateButton_TappedメソッドとcopyButton_Tappedメソッドの末尾にも追加しておいてほしい。すると、ファイルを作成/コピーしたときにもリストが更新されるようになる。

 ちなみにWin 8では、StorageFileQueryResultクラスのContentsChangedイベントを利用することで、フォルダ内のファイルに追加/削除/変更があったときにファイルの一覧表示を更新することも可能だ。

ローカル・ストアのファイルを削除するには?

 StorageFileオブジェクトのDeleteAsyncメソッドを使う。

 先ほどローカル・ストアにコピーしたファイルを、今度は全部削除してみよう。

 画面の適当な場所にもう1つButtonコントロールを配置する。そのTappedイベント・ハンドラ(WP 8ではClickイベント・ハンドラ)で、ローカル・ストアを表すStorageFolderオブジェクトを取得したら、そこにあるファイルをStorageFileオブジェクトとして列挙し、それぞれでDeleteAsyncメソッドを呼び出せばよい。

private async void deleteButton_Tapped(object sender, TappedRoutedEventArgs e)
{
  // ローカル・ストアを表すStorageFolderオブジェクト
  Windows.Storage.StorageFolder folder
    = Windows.Storage.ApplicationData.Current.LocalFolder;

  // フォルダ内の全ファイルを列挙し、それぞれ削除する
  foreach (Windows.Storage.StorageFile file in await folder.GetFilesAsync())
  {
    try
    {
      await file.DeleteAsync();
    }
    catch { }
  }

  // ListBoxコントロールのファイル一覧を更新
  await ListAllFilesAsync();
}

Private Async Sub deleteButton_Tapped(sender As Object, e As TappedRoutedEventArgs)
  ' ローカル・ストアを表すStorageFolderオブジェクト
  Dim folder As Windows.Storage.StorageFolder _
      = Windows.Storage.ApplicationData.Current.LocalFolder

  ' フォルダ内の全ファイルを列挙し、それぞれ削除する
  For Each file As Windows.Storage.StorageFile In Await folder.GetFilesAsync()
    Try
      Await file.DeleteAsync()
    Catch
    End Try
  Next

  ' ListBoxコントロールのファイル一覧を更新
  Await ListAllFilesAsync()
End Sub

ローカル・ストアのファイルを全部削除する(上:C#、下:VB)
このメソッドの第2引数はTappedRoutedEventArgsクラスになっているが、これはWin 8の場合。WP 8ではRoutedEventArgsクラスとなる。

 また、ファイル名が分かっている特定の1ファイルを削除するだけならば、StorageFolderオブジェクトのGetFileAsyncメソッド*7を使ってそのファイルのStorageFileオブジェクトを直接取得し*8、DeleteAsyncメソッドで削除すればよい。

*7 上のコードで列挙に使ったのはGetFilesAsyncメソッド。ファイルを1つだけ取得するのはGetFileAsyncメソッド。紛らわしいが、メソッド名の中のFileが複数か単数かという違いだ。

*8 ファイル名をURIで指定してStorageFileクラスのGetFileFromApplicationUriAsyncメソッドを使うことでも、そのファイルのStorageFileオブジェクトを取得できる。


ローカル・ストアのテキスト・ファイルを読み取るには?

 StorageFileオブジェクトを取得できたら、後はアプリ同梱のテキスト・ファイルを読み取る方法(「WinRT/Metro TIPS アプリに同梱したテキスト・ファイルを読むには?[Win 8/WP 8]」で説明した)と同様である。ただし、URIで直接ファイルを指定する場合のスキーマは「ms-appx:///」ではなく、「ms-appdata:///」を用いる(冒頭に掲載した表を参照)。

 ここでは、列挙したStorageFileオブジェクトの中からユーザーに選択してもらい、それを読み取ってTextBoxコントロールに表示してみよう。

 まず、前述の「ローカル・ストアのファイルを列挙するには?」で作成したListBoxコントロール「fileNameList」に、SelectionChangedイベント・ハンドラを追加し「fileNameList_SelectionChanged」という名前にしておく。fileNameListには、StorageFileオブジェクトのコレクションがバインドしてあるから、ユーザーがこのListBoxコントロールで選択したファイルのStorageFileオブジェクトを、SelectionChangedイベント・ハンドラ内で取得できるのだ。次に、読み込んだテキスト・ファイルの内容を表示するためのTextBoxコントロールを、画面の適当な場所に配置し、「editTextBox」と名前を付けておく。

 SelectionChangedイベント・ハンドラで、次のコードのようにしてユーザーに選択されたテキスト・ファイルを読み取ってTextBoxコントロールに表示する。

private async void fileNameList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
  this.editTextBox.Text = string.Empty;

  // ユーザーに選択されたファイル
  Windows.Storage.StorageFile selectedFile
    = this.fileNameList.SelectedItem as Windows.Storage.StorageFile;
  if (selectedFile == null)
    return;

  // StorageFileオブジェクトからファイルを開いて読み込み、TextBoxに表示する
  using (Stream st = (await selectedFile.OpenReadAsync()).AsStream())
  using (TextReader reader = new StreamReader(st))
  {
    this.editTextBox.Text = await reader.ReadToEndAsync();
  }
}

Private Async Sub fileNameList_SelectionChanged(sender As Object, e As SelectionChangedEventArgs)
  Me.editTextBox.Text = String.Empty

  ' ユーザーに選択されたファイル
  Dim selectedFile As Windows.Storage.StorageFile _
      = DirectCast(Me.fileNameList.SelectedItem, Windows.Storage.StorageFile)
  If (selectedFile Is Nothing) Then
    Return
  End If

  ' StorageFileオブジェクトからファイルを開いて読み込み、TextBoxに表示する
  Using st As Stream = (Await selectedFile.OpenReadAsync()).AsStream(),
        reader As TextReader = New StreamReader(st)

    Me.editTextBox.Text = Await reader.ReadToEndAsync()
  End Using
End Sub

選択されたテキスト・ファイルを読み取って表示する(上:C#、下:VB)
WP 8のコードには、System.IO名前空間のインポートも必要だ。

 なお、Win 8では、次のように簡単に書ける。

// StorageFileオブジェクトからファイルを開いて読み込み、TextBoxに表示する
// using (Stream st = (await selectedFile.OpenReadAsync()).AsStream())
// using (TextReader reader = new StreamReader(st))
// {
//   this.editTextBox.Text = await reader.ReadToEndAsync();
// }
//  ↓
// WP 8との互換を取らなくてもよいなら、1行で書ける
this.editTextBox.Text = await Windows.Storage.FileIO.ReadTextAsync(selectedFile);

' StorageFileオブジェクトからファイルを開いて読み込み、TextBoxに表示する
' Using st As Stream = (Await selectedFile.OpenReadAsync()).AsStream(),
'       reader As TextReader = New StreamReader(st)
'
'   Me.editTextBox.Text = Await reader.ReadToEndAsync()
' End Using
'   ↓
' WP 8との互換を取らなくてもよいなら、1行で書ける
Me.editTextBox.Text = Await Windows.Storage.FileIO.ReadTextAsync(selectedFile)

選択されたテキスト・ファイルを読み取って表示する(Win 8専用版)(上:C#、下:VB)

 このWin 8専用のFileIOクラス(Windows.Storage名前空間)には、1行ずつ読み込むReadLinesAsyncメソッドなどの便利なメソッドがあるので、WP 8との互換性を考えなくてよいときは活用してほしい。

ローカル・ストアのテキスト・ファイルに書き込むには?

 読み込みとよく似た手順になる。ここでは、前述のTextBoxコントロールに表示されている文字列を、ユーザーがListBoxコントロールで選択しているファイルに保存してみよう。

 画面の適当な場所にもう1つButtonコントロールを配置する。そのTappedイベント・ハンドラ(WP 8ではClickイベント・ハンドラ)に次のように記述する。

private async void overwriteButton_Tapped(object sender, TappedRoutedEventArgs e)
{
  // 書き込む内容
  string text = this.editTextBox.Text;

  // ユーザーに選択されたファイル
  Windows.Storage.StorageFile selectedFile
    = this.fileNameList.SelectedItem as Windows.Storage.StorageFile;
  if (selectedFile == null)
    return;

  // StorageFileオブジェクトからファイルを開いて書き込む
  using (Stream st = (await
    selectedFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite)).AsStream())
  using (TextWriter writer = new StreamWriter(st))
  {
    await writer.WriteAsync(text);
  }
}

Private Async Sub overwriteButton_Tapped(sender As Object, e As TappedRoutedEventArgs)
  ' 書き込む内容
  Dim text As String = Me.editTextBox.Text

  ' ユーザーに選択されたファイル
  Dim selectedFile As Windows.Storage.StorageFile _
    = DirectCast(Me.fileNameList.SelectedItem, Windows.Storage.StorageFile)
  If (selectedFile Is Nothing) Then
    Return
  End If

  ' StorageFileオブジェクトからファイルを開いて書き込む
  Using st As Stream = (Await _
    selectedFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite)).AsStream(),
        writer As TextWriter = New StreamWriter(st)

    Await writer.WriteAsync(text)
  End Using
End Sub

ユーザーが選択したファイルにテキストを書き込む(上:C#、下:VB)
上のリストでは、イベント・ハンドラの第2引数はTappedRoutedEventArgsクラスになっているが、これはWin 8の場合。WP 8ではRoutedEventArgsクラスとなる。

 なお、存在しないファイルに書き込むことはできない。その場合は、まず空のファイルを作成してから書き込むようにする。

 また、読み込みと同様に書き込みでも、Win 8では次のように簡単に書ける。

// StorageFileオブジェクトからファイルを開いて書き込む
// using (Stream st = (await selectedFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite)).AsStream())
// using (TextWriter writer = new StreamWriter(st))
// {
//   await writer.WriteAsync(text);
// }
//  ↓
// WP 8との互換を取らなくてもよいなら、1行で書ける
await Windows.Storage.FileIO.WriteTextAsync(selectedFile, text);

' StorageFileオブジェクトからファイルを開いて書き込む
' Using st As Stream = (Await selectedFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite)).AsStream(),
'       writer As TextWriter = New StreamWriter(st)
'
'   Await writer.WriteAsync(text)
' End Using
'  ↓
' WP 8との互換を取らなくてもよいなら、1行で書ける
Await Windows.Storage.FileIO.WriteTextAsync(selectedFile, text)

ユーザーが選択したファイルにテキストを書き込む(Win 8専用版)(上:C#、下:VB)

まとめ

 アプリケーション・データ記憶域では、ApplicationDataクラスを使ってStorageFolderオブジェクトを取得する。アプリケーション・データ記憶域では、自由にファイルのアクセスができるので、StorageFolderオブジェクトを使ってファイルを列挙し、得られたStorageFileオブジェクトを使ってファイルの作成/コピー/削除を行える。また、StorageFileオブジェクトとStreamクラスやTextReader/TextWriterクラス(Win 8ではFileIOクラスでも可)を使って、テキスト・ファイルの読み書きができる。

「WinRT/Metro TIPS」のインデックス

WinRT/Metro TIPS

Copyright© 1999-2017 Digital Advantage Corp. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

Focus

- PR -

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。