Windowsランタイムアプリではテキストファイルの扱い方が独特だ。そこで、本稿ではテキストファイルの読み取り/書き込みを行う方法を解説する。
powered by Insider.NET
テキストファイルを読み書きする。基本的なことではあるが、デスクトップアプリ開発やASP.NETのWeb開発からWindowsランタイムアプリ開発に移ってきた人にとっては、どうすればよいのか分かりにくいかもしれない。そこで本稿では、Windows 8.1とWindows Phone 8.1用のユニバーサルWindowsアプリ、およびWindows 10用のユニバーサルWindowsアプリで共通に使える方法を解説する。なお、本稿のサンプルは「Windows Store app samples:MetroTips #107」からダウンロードできる。
Windows 8.1とWindows Phone 8.1用のユニバーサルWindowsアプリを開発するには、以下の開発環境が必要である。本稿では、無償のVisual Studio Community 2013 with Update 4を使っている。
*1 SLAT対応ハードウエアは、Windows Phone 8.1エミュレーターの実行に必要だ。ただし未対応でも、ソースコードのビルドと実機でのデバッグは可能だ。SLAT対応のチェック方法はMSDNブログの「Windows Phone SDK 8.0 ダウンロードポイント と Second Level Address Translation (SLAT) 対応PCかどうかを判定する方法」を参照。なお、SLAT対応ハードウエアであっても、VM上ではエミュレーターが動作しないことがあるのでご注意願いたい。
*2 事前には「Windows 8.1 Update 1」と呼ばれていたアップデート。スタート画面の右上に検索ボタンが(環境によっては電源ボタンも)表示されるようになるので、適用済みかどうかは簡単に見分けられる。ちなみに公式呼称は「the Windows RT 8.1, Windows 8.1, and Windows Server 2012 R2 update that is dated April, 2014」というようである。
*3 Windows Phone 8.1エミュレーターを使用しないのであれば、32bit版のWindows 8.1でもよい。
*4 マイクロソフトのダウンロードページから誰でも入手できる(このURLはUpdate 4のもの)。
*5 本稿に掲載したコードを試すだけなら、無償のExpressエディションやCommunityエディションで構わない。Visual Studio Express 2013 with Update 4 for Windows(製品版)はマイクロソフトのページから無償で入手できる。Expressエディションはターゲットプラットフォームごとに製品が分かれていて紛らわしいが、Windowsランタイムアプリの開発には「for Windows」を使う(「for Windows Desktop」はデスクトップで動作するアプリ用)。また、2014年11月12日(米国時間)に新しくリリースされたVisual Studio Community 2013 with Update 4(製品版)もマイクロソフトのページから無償で入手できる。Communityエディションは本稿執筆時点では英語版だけなので、同じ場所にあるVisual Studio 2013 Language Packの日本語版を追加インストールし、[オプション]ダイアログで言語を切り替える必要がある。
.NET Frameworkで開発してきた人は、ファイルの読み書きというとSystem.IO名前空間のFileクラスやStreamReader/StreamWriterクラスなどを思い浮かべるだろう*6。しかし、WindowsランタイムではWindows.Storage名前空間のFileIOクラスをよく利用する。System.IO名前空間も使えるが、かえって面倒になる。
Windows.Storage名前空間のFileIOクラスは、それほど大きくないファイルを読み書きしやすい作りになっている。とても簡単にファイルの読み書きができるのだ(それを本稿で解説する)。その半面、メモリに載りきらない大きなファイルや、Unicode以外のエンコーディングは扱えない。また、例えば、XmlSerializerクラスの出力先にもできない。そのような高度な処理が必要なときは、面倒だが.NET Frameworkの世界に移ってSystem.IO名前空間を使うことになる*7。
*6 .NET FrameworkのSystem.IO名前空間のFileクラスはWindowsランタイムアプリでは使えない。StreamReader/StreamWriterクラスはWindowsランタイムアプリで使える。StreamReader/StreamWriterクラスを使ってテキストファイルを読み書きする方法は、次を参照してほしい。
*7 Unicode以外のエンコーディングのテキストファイルを読み込む方法や、XmlSerializerクラスを使う例は、次を参照してほしい。
読み書きの対象とするファイルは、StorageFileオブジェクト(Windows.Storage名前空間)として扱う。ところが、Windowsランタイムアプリでは、ファイルのフルパスを使ってファイルのオブジェクトを得ることはできないのだ。本稿では、StorageFileオブジェクトは取得できているものとして話を進めるが、簡単に紹介しておこう。StorageFileオブジェクトを取得するには、次のような方法を用いる。
FileIOクラスのReadTextAsyncメソッドかReadLinesAsyncメソッドを使えばよい。
ReadTextAsyncメソッドは、テキストファイルの内容全体を一つの文字列として読み取ってくれる(次のコード)。
// 読み取るテキストファイル(何らかの手段で取得したStorageFileオブジェクト)
StorageFile sampleFile = ……省略……
// ファイルの全体を読み取る
string readText = await FileIO.ReadTextAsync(sampleFile);
' 読み取るテキストファイル(何らかの手段で取得したStorageFileオブジェクト)
Dim sampleFile As StorageFile = ……省略……
' ファイルの全体を読み取る
Dim readText As String = Await FileIO.ReadTextAsync(sampleFile)
ReadLinesAsyncメソッドは、読み込んだテキストファイルを行ごとに分解し、文字列のコレクションとして返してくれる(次のコード)。
// 読み取るテキストファイル(何らかの手段で取得したStorageFileオブジェクト)
StorageFile sampleFile = ……省略……
// ファイルを行ごとに分解して読み込む
IList<string> lines = await FileIO.ReadLinesAsync(sampleFile);
foreach (string line in lines)
{
// line変数に1行分の文字列が入っているので、ここで1行に対する処理を行う
System.Diagnostics.Debug.WriteLine(line);
// ファイルの読み込みは完了しているので、ここでファイルを書き換えてもOK!
}
' 読み取るテキストファイル(何らかの手段で取得したStorageFileオブジェクト)
Dim sampleFile As StorageFile = ……省略……
' ファイルを行ごとに分解して読み込む
Dim lines As IList(Of String) = Await FileIO.ReadLinesAsync(sampleFile)
For Each line As String In lines
' line変数に1行分の文字列が入っているので、ここで1行に対する処理を行う
System.Diagnostics.Debug.WriteLine(line)
' ファイルの読み込みは完了しているので、ここでファイルを書き換えてもOK!
Next
FileIOクラスのAppendTextAsyncメソッドかAppendLinesAsyncメソッドを使えばよい。
空のファイル(=サイズが0のファイル)に追加した場合は、次項で説明する上書きと同じ結果になる。
AppendTextAsyncメソッドには、StorageFileオブジェクトと一つの文字列を与える。すると、そのファイルの末尾にその文字列が追加される(次のコード)。
// 書き込むテキストファイル(何らかの手段で取得したStorageFileオブジェクト)
StorageFile sampleFile = ……省略……
// 追加したいテキスト
string text =
@"1行目
2行目
";
// ファイルの末尾にテキストを追加する
await FileIO.AppendTextAsync(sampleFile, text);
' 書き込むテキストファイル(何らかの手段で取得したStorageFileオブジェクト)
Dim sampleFile As StorageFile = ……省略……
' 追加したいテキスト
Dim text As String = "1行目" + vbCrLf _
+ "2行目" + vbCrLf
' ファイルの末尾にテキストを追加する
Await FileIO.AppendTextAsync(sampleFile, text)
AppendLinesAsyncメソッドには、StorageFileオブジェクトと文字列のコレクションを与える。コレクション内のそれぞれの文字列を1行として、そのファイルの末尾に順に追加される(次のコード)。
// 書き込むテキストファイル(何らかの手段で取得したStorageFileオブジェクト)
StorageFile sampleFile = ……省略……
// 追加したいテキストのコレクション
IEnumerable<string> texts = new List<string>()
{
"1行目",
"2行目",
};
// ファイルの末尾にテキストを追加する
await FileIO.AppendLinesAsync(sampleFile, texts);
' 書き込むテキストファイル(何らかの手段で取得したStorageFileオブジェクト)
Dim sampleFile As StorageFile = ……省略……
' 追加したいテキストのコレクション
Dim texts As IEnumerable(Of String) = New List(Of String)() _
From {
"1行目",
"2行目"
}
' ファイルの末尾にテキストを追加する
Await FileIO.AppendLinesAsync(sampleFile, texts)
FileIOクラスのWriteTextAsyncメソッドかWriteLinesAsyncメソッドを使えばよい。
WriteTextAsyncメソッドには、StorageFileオブジェクトと一つの文字列を与える。すると、そのファイルの内容がその文字列で置き換えられる(次のコード)。
// 書き込むテキストファイル(何らかの手段で取得したStorageFileオブジェクト)
StorageFile sampleFile = ……省略……
// 上書きしたいテキスト
string text =
@"1行目
2行目
";
// ファイルの内容を上書きする
await FileIO.WriteTextAsync(sampleFile, text);
' 書き込むテキストファイル(何らかの手段で取得したStorageFileオブジェクト)
Dim sampleFile As StorageFile = ……省略……
' 上書きしたいテキスト
Dim text As String = "1行目" + vbCrLf _
+ "2行目" + vbCrLf
' ファイルの内容を上書きする
Await FileIO.WriteTextAsync(sampleFile, text)
WriteLinesAsyncメソッドには、StorageFileオブジェクトと文字列のコレクションを与える。コレクション内のそれぞれの文字列を1行として、そのファイルの内容を置き換える(次のコード)。
// 書き込むテキストファイル(何らかの手段で取得したStorageFileオブジェクト)
StorageFile sampleFile = ……省略……
// 上書きしたいテキストのコレクション
IEnumerable<string> texts = new List<string>()
{
"1行目",
"2行目",
};
// ファイルを上書きする
await FileIO.WriteLinesAsync(sampleFile, texts);
' 書き込むテキストファイル(何らかの手段で取得したStorageFileオブジェクト)
Dim sampleFile As StorageFile = ……省略……
' 上書きしたいテキストのコレクション
Dim texts As IEnumerable(Of String) = New List(Of String)() _
From {
"1行目",
"2行目"
}
' ファイルを上書きする
Await FileIO.WriteLinesAsync(sampleFile, texts)
以上で、テキストファイルを読み書きする方法の説明は、一通り終了である。ところで、AppendTextAsyncメソッドを使うコードの説明に、複数回に分けて呼び出すとパフォーマンスが落ちると書いた。AppendTextAsyncメソッドの呼び出しごとにファイルのオープン/クローズ処理が走るので、時間がかかるのだ。「そうはいっても大したことじゃないだろう?」と思われるかもしれないので、最後にその検証を行っておこう。数行程度では確かに大したことはないのだが、数百行のオーダーになってくるととんでもないことになるのである。次のコードでは、1000行の書き込みにかかる時間を比較している。
// 冒頭に「using System.Linq;」が必要
// 書き込むテキスト(1000行)
IEnumerable<string> texts = Enumerable.Range(1, 1000).Select(n => n.ToString());
// 何らかの手段で取得したStorageFileオブジェクト
StorageFile sampleFile = ……省略……
// 計測用のタイマーをスタート
var stopWatch = new System.Diagnostics.Stopwatch();
stopWatch.Start();
// 1行ずつ追加書き込み
foreach(var line in texts)
await FileIO.AppendTextAsync(sampleFile, line);
// タイマーを止めて経過時刻表示
stopWatch.Stop();
long time1 = stopWatch.ElapsedMilliseconds;
System.Diagnostics.Debug.WriteLine("AppendTextAsync: {0}ミリ秒", time1);
// 何らかの手段で取得したStorageFileオブジェクト(新しいファイルを用意する)
sampleFile = ……省略……
// タイマーをスタート
stopWatch.Restart();
// まとめて追加書き込み
await FileIO.AppendLinesAsync(sampleFile, texts);
// タイマーを止めて経過時刻表示
stopWatch.Stop();
long time2 = stopWatch.ElapsedMilliseconds;
System.Diagnostics.Debug.WriteLine("AppendLinesAsync: {0}ミリ秒", time2);
// PCでの出力例:
// AppendTextAsync: 9542ミリ秒
// AppendLinesAsync: 8ミリ秒
' 書き込むテキスト(1000行)
Dim texts As IEnumerable(Of String) = Enumerable.Range(1, 1000) _
.Select(Function(n) n.ToString())
' 何らかの手段で取得したStorageFileオブジェクト
Dim sampleFile As StorageFile = ……省略……
' 計測用のタイマーをスタート
Dim stopWatch = New System.Diagnostics.Stopwatch()
stopWatch.Start()
' 1行ずつ追加書き込み
For Each line In texts
Await FileIO.AppendTextAsync(sampleFile, line)
Next
' タイマーを止めて経過時刻表示
stopWatch.Stop()
Dim time1 As Long = stopWatch.ElapsedMilliseconds
System.Diagnostics.Debug.WriteLine("AppendTextAsync: {0}ミリ秒", time1)
' 何らかの手段で取得したStorageFileオブジェクト(新しいファイルを用意する)
sampleFile = ……省略……
' タイマーをスタート
stopWatch.Restart()
' まとめて追加書き込み
Await FileIO.AppendLinesAsync(sampleFile, texts)
' タイマーを止めて経過時刻表示
stopWatch.Stop()
Dim time2 As Long = stopWatch.ElapsedMilliseconds
System.Diagnostics.Debug.WriteLine("AppendLinesAsync: {0}ミリ秒", time2)
' PCでの出力例:
' AppendTextAsync: 9774ミリ秒
' AppendLinesAsync: 10ミリ秒
テキストファイルの読み書きは、Windows.Storage名前空間のFileIOクラスを使うと簡単にできる。ただし、メモリに載りきらないほど大きなファイルや、Unicode以外のエンコーディングのファイルは扱えないなど、簡単に使える代償としての限界もある。簡単に済ませられるときはFileIOクラスを使い、そうでなければ.NET Frameworkの世界に移ってSystem.IO名前空間を使うことになる。うまく使い分けてほしい。
Microsoft Virtual Academy(MVA)では、マイクロソフトのトレーニングコースが無償で受講できる。多数あるコースの中から、いち早くWindows 10のユニバーサルWindowsアプリ開発に挑戦してみたいという人にぴったりのものを紹介する。
現時点で詳細な情報はどうしても英語のものになってしまう。ここに挙げた英語のコンテンツは資料をダウンロードできるので、まずそれを読んでからヒアリングに挑戦するとよいだろう。
Copyright© Digital Advantage Corp. All Rights Reserved.