そこで,FileStreamクラス(AIRで追加されたファイルの読み書き用クラス)を使い,
XMLのメソッド1つで,非同期に読み書きをするXMLManagerクラスを作ってみた.
package { import flash.events.EventDispatcher; import flash.events.OutputProgressEvent; import flash.events.Event; import flash.filesystem.File; import flash.filesystem.FileMode; import flash.filesystem.FileStream; /** XML用クラス * @auther kusamochi * @extend EventDispatcher */ public class XMLManager extends EventDispatcher { public static const READ_COMPLETE:String = "read_complete"; public static const READ_CLOSE:String = "read_close"; public static const WRITE_PROGLESS:String = "write_progress"; public static const WRITE_CLOSE:String = "write_close"; private var _xml:XML; // [read]xmlファイルの実体 private var fileStream:FileStream; private var _mode:String; //コンストラクタ public function XMLManager() { _mode = "NormalMode"; } // 明示的な参照解除メソッド public function deleteReference():void { if(fileStream) { if(_mode == "ReadMode") { fileStream.removeEventListener(Event.COMPLETE, readStreamCompleteHandler); fileStream.removeEventListener(Event.CLOSE, readStreamCloseHandler); } else if(_mode == "WriteMode") { fileStream.removeEventListener(OutputProgressEvent.OUTPUT_PROGRESS, writeStreamOutputProgressHandler); fileStream.removeEventListener(Event.CLOSE, writeStreamCloseHandler); } } } // ファイル読み込み public function readXML(file:File):void { trace("XMLManager::readXML"); trace("Reading : " + file.nativePath); _mode = "ReadMode"; fileStream = new FileStream(); fileStream.addEventListener(Event.COMPLETE, readStreamCompleteHandler); fileStream.addEventListener(Event.CLOSE, readStreamCloseHandler); fileStream.openAsync(file, FileMode.READ); } // ファイル出力 public function writeXML(file:File):void { trace("XMLManager::writeXML"); trace("Writing : " + file.nativePath); _mode = "WriteMode"; fileStream = new FileStream(); fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, writeStreamOutputProgressHandler); fileStream.addEventListener(Event.CLOSE, writeStreamCloseHandler); fileStream.openAsync(file, FileMode.WRITE); fileStream.writeMultiByte(_xml.toXMLString(), File.systemCharset); } public function printXML():void { trace(_xml.toXMLString()); } // EventHandler /////////////////////////////////////////////////////////// // Read ---------------------------------------- // Readストリームがクローズ private function readStreamCloseHandler(event:Event):void { trace("XMLManager::readStreamCloseHandler"); fileStream.removeEventListener(Event.COMPLETE, readStreamCompleteHandler); fileStream.removeEventListener(Event.CLOSE, readStreamCloseHandler); _mode = "NormalMode"; // カスタムイベントを配信する super.dispatchEvent(new Event(READ_CLOSE)); } // 読み込み完了 private function readStreamCompleteHandler(event:Event):void { trace("XMLManager::readStreamCompleteHandler"); var tmpStr:String = fileStream.readMultiByte(fileStream.bytesAvailable, File.systemCharset); fileStream.close(); _xml = new XML(tmpStr); // カスタムイベントを配信する dispatchEvent(new Event(READ_COMPLETE)); } // write -------------------------------------- // Writeストリームがクローズ private function writeStreamCloseHandler(event:Event):void { trace("XMLManager::writeStreamCloseHandler"); fileStream.removeEventListener(OutputProgressEvent.OUTPUT_PROGRESS, writeStreamOutputProgressHandler); fileStream.removeEventListener(Event.CLOSE, writeStreamCloseHandler); _mode = "NormalMode"; // カスタムイベントを配信する super.dispatchEvent(new Event(WRITE_CLOSE)); } // Write進行中 private function writeStreamOutputProgressHandler(event:OutputProgressEvent):void { trace("XMLManager::writeStreamOutputProgressHandler"); if(event.bytesPending == 0){ fileStream.close(); } // カスタムイベントを配信する super.dispatchEvent(new OutputProgressEvent(WRITE_PROGLESS)); } // getter //////////////////////////////////////////////////// // XMLオブジェクトを返す(他のクラスからのアクセスに対応) public function get xml():XML { return _xml; } // mode public function get mode():String { return _mode; } // setter ////////////////////////////////////////////// public function set xml(setXML:XML) { _xml = setXML; } } }
FileStreamクラスのファイルオープンには,openメソッド,openAsyncメソッドの2つがある.
openメソッドを使うと,それ以降のFileStreamの処理は,その行の処理が終わるまで次の行を実行しない.
でも,それだと,ロード対象のサイズが大きくなった場合などに遅延が起きてしまう.
それを避けたいのなら,openAsyncメソッドでファイルオープンする.
openAsyncにすると,各処理ごとにイベントを発行する.
つまり,FileStreamのオブジェクトにaddEventListenerしとけば,読み込み終わりとか判定できるわけです.
そこで,上記のXMLManagerでは,各イベントを利用してMXLの読み書きを行い,さらにカスタムイベントを配信する.
EventDispatcherを継承したのはこのため.
これ,作るときに気づいたんだが,
READモードだとcompleteイベント発生するのに,WRITEモードではcompleteイベント発生しないんだね.
最初気づかずにWRITEモードでもcompleteでファイルクローズしてたから,
イベント自体が発生してないからクローズされていないってことで,
上書き時にエラー出て散々ハマりましたw
しょうがないんで,OutputProgressイベント(出力中に定期的に発生するイベント)を使って,
bytesPending(残りの書き込みバイト数)がゼロになったときにクローズするようにしてみた.
0 件のコメント:
コメントを投稿