.NETのStream系に慣れてるせいか、とても癖があるように感じてしまうWinRTのStream。ちょっと使ってみたいと思います。
まず、ファイルにデータを書き込むところから。 ファイルに書き込む処理には便利な機能があって、書き込みをトランザクションとして扱ってくれる機能があります。StorageFileオブジェクトのOpenTransactedWriteAsyncメソッドでトランザクション開始して、Streamプロパティで取得できるStreamにデータを書き込めばOKです。
Stream生のままだと低レベルすぎるのでDataWriterでラップして各型ごとのデータ書き込みメソッドでデータを書き込むのが幾分か楽です。
以下の例では、文字列長と、文字列を書き込んでいます。全てIOのある処理は非同期なのがWinRTの特徴ですよね。
var file = await ApplicationData.Current.LocalFolder.CreateFileAsync( "sample.txt", CreationCollisionOption.ReplaceExisting); using (var tx = await file.OpenTransactedWriteAsync()) using (var w = new DataWriter(tx.Stream)) { var data = "Hello world " + DateTime.Now; var buff = Encoding.UTF8.GetBytes(data); w.WriteInt32(buff.Length); w.WriteString(data); await w.StoreAsync(); await tx.CommitAsync(); }
とまぁ、書き込みはいいとして読み込みが凄い癖があります。
読み込みはDataReaderでStreamをラップして使えばいいんですが、こいつがLoadAsyncでバッファに指定したサイズだけデータを読み込んで、Read型名って名前のメソッドでバッファからデータを読み込みます。LoadAsyncメソッドが非同期メソッドです。Read型名は同期です。つまりRead型名ではIOが発生しないと。あらかじめ必要なデータをLoadAsyncでバッファに読み込んでおかないといけない。難しい。
ということで、先ほど書き込んだデータを読み込むコードは以下のようになります。LoadAsyncでintのサイズだけデータを読み込んで、ReadInt32で読み込んだデータをint型として取りだしています。そして、同じ要領で文字列も読み込んでいます。
var data = default(string); var file = await ApplicationData.Current.LocalFolder.TryGetItemAsync("sample.txt"); if (file == null) { return; } using (var s = await ((StorageFile)file).OpenReadAsync()) using (var r = new DataReader(s)) { await r.LoadAsync(sizeof(int)); var length = r.ReadInt32(); await r.LoadAsync((uint)length); data = r.ReadString((uint)length); } var dialog = new MessageDialog(data); await dialog.ShowAsync();
個人的にはAsStreamとかでSystem.IO.Streamにしてしまって操作するけどね!