finally節にclose()メソッドを記述しています。
readUTFBytes()メソッドには引数として読み込むデータの長さを指定します。ここで指定しているFileStream.bytesAvailableは、入力バッファから現在どれだけのデータが読み込み可能か示すプロパティです。前述のようにopen()メソッドの場合は次の処理に移った時点でバッファへの読み込みが完了しているので、すべてのデータを一度に取得できます。なお、改行コードCR+LFをそのまま表示すると2つの改行コードとして認識されるため、テキストエリアへ設定する前にString.replace()メソッドでLFのみに置換しています。
次は上記のサンプルを非同期処理に変更してみましょう。
非同期処理の場合、バッファへデータが入力される度にProgressEvent.PROGRESSイベントが配信され、バッファへの入力が完了するとEvent.COMPLETEイベントが配信されます。また、エラー発生時に配信されるIOErrorEvent.IO_ERRORイベント、ファイルのクローズ時に配信されるEvent.CLOSEイベントもあります。これらのイベントを処理するには、ファイルをオープンする前にイベントハンドラを登録しておく必要があります。
openAsync()メソッドでファイルをオープンするとバッファへのデータ入力が開始されるので、完了イベントを受けてreadUTFBytes()メソッドを実行します。このようにバッファからの読み込み自体は同期処理となります。
ファイルの書き出し
書き出しの手順も読み込みの場合とそれほど変わりません。同期処理の場合、ファイルのモードと書き出し時のメソッドが違うだけです。以下のサンプルは、ボタンをクリックするとテキストエリアの内容をsample.txtとして書き出します。
FileMode.READ以外のすべてのモードで書き出しが可能ですが、通常はファイル全体を書き換える処理がほとんどでしょう。その場合はFileMode.WRITEを指定します。UTF-8でテキストファイルを書き出す際にはwriteUTFBytes()メソッドを使い、書き出したい文字列を引数に指定します。
次は非同期処理のサンプルです。
非同期処理で書き出す場合、出力バッファに格納されたデータが定期的にファイルに書き込まれます。進行状況の確認にはOutputProgressEvent.OUTPUT_PROGRESSイベントを使い、OutputProgressEvent.bytesPendingプロパティでバッファに残っているバイト数を確認できます。もっとも、書き出し処理の場合は残りのバイト数を気にすることなく、先にclose()メソッドでファイルをクローズできます。するとバックグラウンドで書き出し処理が終わった時にEvent.CLOSEイベントが配信されます。書き出し処理ではEvent.COMPLETEイベントは配信されません。
様々な読み書き用メソッド
FileStreamクラスにはreadUTFBytes()やwriteUTFBytes()以外にも、データ形式に応じた20個以上の読み書き用メソッドがあります(メソッド名がreadやwriteで始まるもの)。すべては紹介できないので、代表的なもの挙げておきましょう。
readMultiByte()、writeMultiByte()は任意の文字コードを使ってファイルを読み書きできます。サポートしている文字コードはActionScript 3.0のリファレンスを参考にしてください。Shift-JISであれば次のように読み込めます(エラー処理等は省略しています)。
また、OSのデフォルト文字コードがFile.systemCharsetプロパティで取得できるので、それを指定することもできます。
readObject()、writeObject()はActionScriptオブジェクトの保存に使える便利なメソッドです。ActionScriptオブジェクトはAMF(Action Message Format)形式にシリアライズされて保存されます。例えば、次のコードはアプリケーションウィンドウの位置とサイズを示すNativeWindow.boundsプロパティをオブジェクトとして保存します。
これをアプリケーション起動時にreadObject()で読み込み、boundsプロパティに設定し直せば、前回表示していた状態に戻すことができます。registerClassAlias()はオブジェクトの型を維持するために必要メソッドです。保存時だけでなく読み込み時にも必要な処理なので、アプリケーション起動時に一度実行しておくとよいでしょう。実行しない場合、汎用オブジェクトとして扱われます。
ランダムアクセス
FileStream.positionプロパティを使うと、ファイル内のどの位置から読み書きを行うか指定できます。ただし、常にファイル全体を上書きするWRITEモードや常にファイル末尾に追記するAPPENDモードでは効果がありません。また、非同期処理で読み込みを行っている場合には、バッファに入力されている範囲内でのみ移動できます。
ファイルへランダムアクセスができると、例えばMP3ファイルのID3タグを取得できます。ID3v1ではファイルの末尾128バイトに情報があります。ID3タグの仕様については触れませんが、曲名を取得したければ、先頭の"TAG"という識別子に続く30バイト分を読み込みます。
positionプロパティは読み書き処理を実行した分だけ自動的に移動します。上記の例で言うと、readMultiByte()実行後の値は30バイト分進んでいます。そのままさらに30バイト分読み込めばアーティスト名を取得できます。positionプロパティはメディアの記録再生ヘッドのようなものです。
ファイルピッカー
ファイルやファイルの保存先をユーザに選択させたい場合があります。Fileクラスにはそのためのメソッドが用意されており、OS標準のダイアログを利用できます。
browseForDirectory() | フォルダ選択ダイアログを表示 |
browseForOpen() | ファイル選択ダイアログを表示 |
browseForOpenMultiple() | 複数ファイル選択ダイアログを表示 |
browseForSave() | ファイル保存ダイアログを表示 |
※Beta 1 リリースで筆者が確認した範囲では、Macintoshで動作するのはbrowseForSave()だけです。それ以外を実行するとアプリケーションが落ちてしまいます。Windowsでは問題ありません。
次のサンプルは、ボタンをクリックするとファイル選択ダイアログを表示します。ファイル形式のフィルタを指定して、JPG/PNG/BMPファイルのみが表示されるようにしています。
ダイアログの選択ボタンやキャンセルボタンが押された時の処理は、Event.SELECTおよびEvent.CANCELイベントに対するイベントハンドラで行います。選択されたファイルやディレクトリはEvent.targetプロパティからFileオブジェクトとして取得できます。これは他のダイアログの場合も同様です。ただし、browseForOpenMultiple()だけはEvent.SELECTの代わりにFileListEvent.SELECT_MULTIPLEイベントを使います。この場合、選択されたファイルはFileListEvent.filesプロパティからFileオブジェクトの配列として取得します。