ファイルのオープン/クローズ
前回はFileオブジェクトを使ってファイルのコピーや削除といった操作を行いました。AIRアプリケーションは,ファイルの内容を読み込んだり,ファイルにデータを書き込んだりもできます。ファイルの読み書きを行うには,Fileクラスの他にFileStreamクラスを使用します。
読み書きの対象となるファイルは,処理を行う前にオープンし,処理が終わったらクローズする必要があります。オープンしている間は,他のアプリケーションから見ると使用中ということです。オープンはFileStreamクラスのopen()メソッドまたはopenAsync()メソッドで行います。前者は同期メソッド,後者は非同期メソッドです。同期/非同期については前回の記事を参考にしてください。クローズはclose()メソッドで行います。
open()メソッドとopenAsync()メソッドは,どちらも2つの引数を取ります。第1引数は操作対象のファイルを指定したFileオブジェクト,第2引数はファイルモードです。ファイルモードとは,どのような操作を前提にファイルをオープンするか指定するものです。指定できる値はFileModeクラスの定数として定義されていて,次の4つがあります。
| FileMode.READ | 読み込み専用。 |
| FileMode.WRITE | 書き込み専用。ファイルは常に上書きされる。ファイルが存在しなければオープン時に作成される。 |
| FileMode.APPEND | 書き込み専用。データは常にファイル末尾に追記される。ファイルが存在しなければオープン時に作成される。 |
| FileMode.UPDATE | 読み書き両用。ファイルの任意の位置から読み書き可能。ファイルが存在しなければオープン時に作成される。 |
open()メソッドもopenAsync()メソッドも,READまたはUPDATEを指定してファイルをオープンすると,すぐにランタイム内部の入力バッファにデータを読み込み始めます。同期メソッドであるopen()の場合,バッファにすべてのデータが格納されてから次の処理に移りますが,非同期メソッドのopenAsync()の場合はバッファへの読み込みをイベントで監視して必要な処理を行います。
ファイルの読み込み
では,UTF-8のテキストファイルを読み込んでみましょう。次のサンプルは,同期処理でファイルを読み書きする際の基本的な流れです。ボタンをクリックするとデスクトップ上のsample.txtを読み込みテキストエリアに表示します。
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="340" height="300">
<mx:Script>
<![CDATA[
import flash.filesystem.*;
private function readData():void {
var file:File = File.desktopDirectory.resolve("sample.txt");
var stream:FileStream = new FileStream();
try {
stream.open(file, FileMode.READ);
var str:String = stream.readUTFBytes(stream.bytesAvailable);
output.text = str.replace(/\r\n/g, "\n");
} catch (error:IOError) {
trace(error.message);
} finally {
stream.close();
}
}
]]>
</mx:Script>
<mx:TextArea x="20" y="20" id="output" width="300" height="200" fontSize="16"/>
<mx:Button x="136" y="246" label="読み込み" click="readData()"/>
</mx:WindowedApplication>
ここでは読み込みのみを行うので,open()メソッドでFileMode.READを指定してオープンします。続いて実行しているreadUTFBytes()がUTF-8のデータを読み込むメソッドです。ファイルが見つからなかったり読み込めなかったりした場合,これらのメソッドはIOErrorをスローします。エラーが発生するしないに関わらずファイルはクローズしておきたいので,finally節にclose()メソッドを記述しています。
readUTFBytes()メソッドには引数として読み込むデータの長さを指定します。ここで指定しているFileStream.bytesAvailableは,入力バッファから現在どれだけのデータが読み込み可能か示すプロパティです。前述のようにopen()メソッドの場合は次の処理に移った時点でバッファへの読み込みが完了しているので,すべてのデータを一度に取得できます。なお,改行コードCR+LFをそのまま表示すると2つの改行コードとして認識されるため,テキストエリアへ設定する前にString.replace()メソッドでLFのみに置換しています。
次は上記のサンプルを非同期処理に変更してみましょう。
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="340" height="300">
<mx:Script>
<![CDATA[
import flash.filesystem.*;
private var stream:FileStream;
private function readData():void {
var file:File = File.desktopDirectory.resolve("sample.txt");
stream = new FileStream();
stream.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
stream.addEventListener(ProgressEvent.PROGRESS, onInputProgress);
stream.addEventListener(Event.COMPLETE, onInputComplete);
stream.addEventListener(Event.CLOSE, onCloseFile);
stream.openAsync(file, FileMode.READ);
}
private function onIOError(event:IOErrorEvent):void {
trace("I/Oエラー");
stream.close();
}
private function onInputProgress(event:ProgressEvent):void {
trace(stream.bytesAvailable + "バイト読み込み済み");
}
private function onInputComplete(event:Event):void {
try {
var str:String = stream.readUTFBytes(stream.bytesAvailable);
output.text = str.replace(/\r\n/g, "\n");
} catch (error:IOError) {
trace(error.message);
} finally {
stream.close();
}
}
private function onCloseFile(event:Event):void {
trace("ファイルをクローズしました");
}
]]>
</mx:Script>
<mx:TextArea x="20" y="20" id="output" width="300" height="200" fontSize="16"/>
<mx:Button x="136" y="246" label="読み込み" click="readData()"/>
</mx:WindowedApplication>
非同期処理の場合,バッファへデータが入力される度にProgressEvent.PROGRESSイベントが配信され,バッファへの入力が完了するとEvent.COMPLETEイベントが配信されます。また,エラー発生時に配信されるIOErrorEvent.IO_ERRORイベント,ファイルのクローズ時に配信されるEvent.CLOSEイベントもあります。これらのイベントを処理するには,ファイルをオープンする前にイベントハンドラを登録しておく必要があります。
openAsync()メソッドでファイルをオープンするとバッファへのデータ入力が開始されるので,完了イベントを受けてreadUTFBytes()メソッドを実行します。このようにバッファからの読み込み自体は同期処理となります。

