忍者ブログ
研究室生活のメモ・・・だった過去の遺産。移転先→http://negimochix2.blogspot.com/
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

都合上,XMLを自由に読み書きする必要が出てきた.

そこで,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(残りの書き込みバイト数)がゼロになったときにクローズするようにしてみた.

PR
Fileクラスは,AIRで追加された,一括したファイル・ディレクトリ管理ができる万能クラス.
便利なのはいいんだけど,セキュリティーエラーにハマっちゃって・・・.
ハマった割にはたいしたこと無かったけど,知らなかったら解決しない問題なのでメモしておく.

// 保存先
var oldPlayData:File = (File.applicationDirectory).resolvePath("pd.ini");
// 一時保存先
var newPlayData:File = File.createTempFile();

// どこかでoldPlayDataの内容を読み込み

// どこかでoldPlayDataから更新された内容をnewPlayDataに一時的に保存

// 以下,ウインドウを閉じるときに
// newPlayDataが存在するか確認
if(newPlayData.exists) {
  try {
    // newPlayDataの内容をoldPlayDataにコピー
    newPlayData.copyTo(oldPlayData, true);
  }
  catch(error:Error) {
    trace(error.message);
  }

  try {
    // newPlayDataを削除
    newPlayData.deleteFile();
  }
  catch(error:Error) {
    trace(error.message);
  }
}
以下,プログラムの構成.

静的プロパティFile.applicationDirectoryはアプリケーションのインストール先を指すFileオブジェクト.
さらに,resolvePathメソッドでpd.iniというファイルパスを作成し,ファイルの保存先(oldPlayData)とする.

さらに,File.createTempFileメソッドで一時保存先(newPlayData)を確保.

oldPlayDataから更新内容があった場合,一時保存先に更新内容を記録しておく.
このへんのプログラムは本題でないので省略.

ウインドウを閉じる時,
一時保存先からコピーしてpd.iniに書き込んだのち,一時保存先のファイルを削除する.


これだけのプログラムなのに,何故か最初のtryで「SecurityError: fileWriteResource」


どーなってんのってググってみたら,
どうやら,applicationDirectoryにおいて,ファイルを作成・書き込みすることはセキュリティ上認められていないらしい.

( ´゚д゚`)エー

その抜け道として,コピー前に,
  oldPlayData = new File(oldPlayData.nativePath);

というように,一度nativePath(絶対パスのString)からFileクラスを再宣言すると,
セキュリティエラーから抜けられるとか.

でもそのかわり,
・AIRアプリケーションアンインストール時に自分で作成したファイルは削除されない
・作成したファイルが残っている状態で再インストールしようとするとエラーが発生
引用: applicationDirectory配下のファイルにアクセスする方法 - Fores Labs

あーだめだこれw

素直に,
// アプリケーションのプライベート記憶領域を指定
var oldPlayDataFile:File = (File. applicationStorageDirectory).resolvePath("pd.ini");
とするのが妥当かな.
これだと,applicationStorageDirectoryは,実際のディレクトリ位置がOSによって,
・Windowsの場合
  C:\Documents and Settings\[ユーザ名]\Application Data\[AIRアプリID]
  \Local Store

・Macの場合
  HD/Users/[ユーザー名]/Library/Preferences/[AIRアプリID]/Local Store/
となるので,上記のresolvePathでpd.iniを指定した場合は,
・Windowsの場合
  C:\Documents and Settings\[ユーザ名]\Application Data\[AIRアプリID]
  \Local Store\pd.ini

・Macの場合
  HD/Users/[ユーザー名]/Library/Preferences/[AIRアプリID]/Local Store/pd.ini
となる.
どうやら,このディレクトリはアンインストールと同時に消去されるらしい.


結論:
applicationDirectoryはファイルの書き込みには使用しない
(使うなら読み込み時.事前にパッケージしたswfとか画像データとかを読み込むのに使えばいい)

今、あるサイトに運営において必要なFlash(正確にはAIR)を制作中.

Tweenerの最新バージョンが気になったので調べてみた.
どうやら最近,ちょっとしたごたごたがあったみたい.

TweenerはFlashを記述するAction Script 2.0,3.0のライブラリ.
オブジェクトを動きを簡単にかつ詳細に設定できる万能ライブラリで,かなり多くの人に使われている.
というか,普通にプロも使ってそう.
Google Codeで配布されてます.
http://code.google.com/p/tweener/

現状の最新版は1.33.74.
その前バージョン1.32.74において, 「Tweenerの上書き」の設定について不評があり,1.33.74ではそれが修正されている.


そもそもTweenerの上書きって?
同じオブジェクトに対してTweenを連続で設定したとき,以前のバージョンまでは自動で上書きされてていた.
var mySquare:MySquare = new MySquare(); // 正方形
var myCircle:MyCircle = new MyCircle(); // 円
mySquare.x = 20;
mySquare.y = 20;
stage.addChild(mySquare);
myCircle.x = 20;
myCircle.y = 20;
stage.addChild(myCircle);
Tweener.addTween(mySquare, {x:160, time:4, transition:"linear"});
Tweener.addTween(mySquare, {x:160, time:2, transition:"linear"});
Tweener.addTween(myCircle, {x:160, time:4, transition:"linear"});
Tweener.addTween(myCircle, {y:160, time:2, transition:"linear"});

▲実行結果

x座標を連続で設定したmySquareは,後に書いた方に上書きされていることが確認できる.

ver.1.32.74の変更点
Tweenの上書きをオプション扱いにする.その際,デフォルトではfalse(無効)
なので,上のコードをver.1.32.74で実行すると,


▲ver.1.32.74で実行

mySquareの設定が上書きされなくなる.

そのかわり,オプションに,
Tweener.addTween(mySquare, {x:160, time:4, transition:"linear"});
Tweener.addTween(mySquare, {x:160, time:2, transition:"linear", overwrite:true});
overwriteオプションを追加することで,前バージョンと同様に上書きされる
しかし,前バージョンのライブラリを使っていた人にとっては,バージョンアップによって動作に問題が生ずる可能性がある.

ver.1.33.74の変更点
そこで,現最新バージョンでは,Tweenの上書き設定をする静的プロパティ「autoOverwrite」を追加し,上書き設定のデフォルトをtrueとした.
これにより,前バージョンまで使っていたASであっても正常に動作し,かつ上書きの有無を設定できるようになった.

つまり,上書きをしたかったら,今まで通りそのままでおk.
上書きしたくないのなら,上記ver.1.32.74のようにオプションで1つ1つ設定するか,以下のようにして設定する.
Tweener.autoOverwrite = false;
Tweener.addTween(mySquare, {x:160, time:4, transition:"linear"});
Tweener.addTween(mySquare, {x:160, time:2, transition:"linear"});
ver.1.32.74で上書き設定をデフォルトでfalseにした理由は,その処理速度の問題から.
Flashはしばしばというか,かなりの場合,処理速度が重要なキーとなる.
まあ,スクリプト言語だし,C言語に比べれば計算速度自体かなり遅い.
だから,できるだけ速くする努力は必要.

今回の「上書き設定」は,上書きしないことがわかっているなら,最初からfalseにしといたほうがコストが少なくすむ.
例のFlashの実行結果からように,以前のバージョンのTweenerでは,同じオブジェクトがTweenを設定されたとき,まず,同じプロパティがあるかどうかを探索する.
同じプロパティがあった場合は,その設定を上書きして,ない場合はそのまま設定を追加する.

・・・ということは,今まで作った自分のプログラムもfalseにした方が効率上がるのかな?
どこかで上書きしてたら困るけども.
どれくらい速くなるかは要検証.
http://www.jrhokkaido.co.jp/kitaca/page_5.html

なんというAIRの有効活用.

動きがかわいすぎるw

あまりにもかわいいのでブログパーツつけてしまったw

個人的にかわいさでいったら

Kitaca > Suica > |越えられない壁| > Pasmo

だと思うんだ.

Kitaca/Suica相互利用で,あえて東京でKitaca使うと何故だか

勝った気分になるw

いやー,やっぱり,北海道は最高だ.(よく分からない結論w)



自分も嫁でこういうの作ればいいんだけど,

というか,実際に完成に近い部分まで作ってはいるけれど,

なかなかバグがとれなくて,現在,放置プレイ状態.


うーん,やっぱ暇を見て作らないとね.

これ見たら少しモチベーションが上がった.
AIRだと,SQLiteを扱うクラスがあるらしい.

でも,MySQLは対応していなかったみたい・・・.

調べるとどうやら,asSQLはMySQLをサポートしてくれるそうな.

asSQL - Google Code


よし.使ってみよう!

と思ったら・・・


SWFから直にMySQLへ接続するということは、
クライアントからデータベースサーバへ直にソケット接続が必要

【抜粋】気ままな開発メモ:asSQLを使ってみる


ですよねー

ローカルなネットワークじゃないと無理ってことか・・・.

同サイトには,「限られたネットワークであれば非常に有効」とも書いてあるだけにおしいな.

せっかく面白そうなの見つけたのに.

Flashからphpにデータ送ってSQLに登録って感じにしないとだめか.



世の中ってそううまくいきませんよね.


趣味も就活も
最近(でもないか・・・),ニコ動でswfを直接うpすることが可能になった.
ベクターグラフィックスをそのままうpできることに相当するのでかなり興味深い.
今日見つけた動画は↓




元々「アイシンクアンシン」自体は若干Pによる初音ミクのオリジナル楽曲.
この動画は,それを「歌ってみた」動画からPVにしたようで.

アイシンクアンシンは若干好きな曲で
・・・と曲自体の話をするんじゃなかったw

このPVのデザインはデザインがシンプル.
使ってる技法もシンプル.
でも,こうしたシンプルさが曲のイメージにうまく合っている.
あえて「歌ってみた」のPVにしたのも,原曲の動画のイメージを壊さないための配慮ではないかと思った.

ただ・・・ラストだけちょっと重かったように見えたのは,演出なのだろうか.
トゥイーン対象が多くなったりalpha値弄ったオブジェクトが多いと重くなってしまうということはあるかもしれない.
これは,ニコ動プレイヤーにおけるLoaderのバッファが少なく設定されているということ?
それとも,単にマシンスペックの問題?
はたまた,ニコ動にswfをうpする段階で,なんらかの原因発生するバグ?
いずれにしても,これはswfのうpにおける欠点になりそうな感じ.

あと,この動画では途中で停止しても部分的にオブジェクトが動いていたりする.
これは,メインのタイムラインじゃなくて,入れ子にしたMovieClipの中のタイムラインで動かしているからなのかな?
部分的に動いてるのを見るにそんな気がする.
ということは,ニコ動ではメインタイムラインだけ止めていて,他は止めてないってことになるの?

うーんよくわからないなぁ・・・

今度できたら実験してみたい.
Infomation
くさもち 【中の人】
・くさもち
・ボカロ廃大学院生
・βからのニコ厨
・もちろん非リア充
・ミクZ4 第二期個人スポンサー

【メール】
・negimochi.tabetai(゚Д゚)gmail.com
(゚Д゚)→@

【その他やってるもの】
Twitter

・これは痛いピアプロ
・過去の遺産smart.fm

【作ったもの】
・製作に参加したDTX GDPメインサイト
で,実際に作ったIRページ
カレンダー
10 2024/11 12
S M T W T F S
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Heartsnative
『Heartsnative/MOSAIC.WAV×鶴田加茂 feat.初音ミク』応援中!
VOCALOID Ranking Watcher
新曲は常にチェックすべし。
真・フルみっくすプレイヤー
おすすめ記事
jubeat ripples
今更やってみる