[AS3] AIRでJSONテキストファイルの入出力をしたい

2013/11/14

こんにちは。きんくまです。

AIRでアプリのデータを保存するときにJSON形式のテキストデータを使おうと思いました。
それで、以前はas3corelibっていうライブラリを使えば良かったのですが、AIRの3.0からはネイティブでJSON形式が扱えるようになってました。

>> JSON – AS3
>> Using native JSON functionality

クラスメソッドさんのところに詳しく載ってました
>> Flash Player 11で追加されたJSONクラスのパフォーマンスと機能

それで、上の記事にもあるように、JSON. stringify()、 JSON. parse()の第二引数に関数を書いてもよいのですが、
自作クラスが入れ子になっていると、その関数が大きなものになっちゃいます。
なので、できれば分割して書きたいなと。

分割して書く

それで、まず自作クラスのインスタンスのJSON化、出力の方ですが、

function toJSON(s:String):*

というメソッドを自作クラスの中で実装すると、ネイティブのJSON.stringifyはそのメソッドを感知してそいつを使ってJSONオブジェクト化した後にJSON文字列にしてくれます。

なので、保存したいプロパティだけをこのメソッドの中にいれとけば大丈夫です。

あとは自作クラスのインスタンスへJSONオブジェクトを取り込む入力の方は、適当な関数を用意します。今回は

function importJSON(json:Object):void;

という名前のものにしました。
toJSONに対して、fromJSONという名前の方がいいと思ったのだけど、それだとわかりにくいのでこの名前にしました。

入力と出力用の関数が用意できたので、この2つをまとめたインターフェースを用意してあげます。

IJSONCompatible

package
{
	public interface IJSONCompatible
	{
		function toJSON(s:String):*;
		function importJSON(json:Object):void;
	}
}

これで、このインターフェースを実装してあるデータは、JSONの入出力ができることが保証されました。
(別になくてもいいんだけど、あとからソース見たときにわかりやすいかなーと)

サンプルのモデルデータを用意します。
さきほどのインターフェースを実装してます。

Person

package
{
	public class Person implements IJSONCompatible
	{
		protected static const JSON_PROP_FIRST_NAME:String = "firstName";
		protected static const JSON_PROP_LAST_NAME:String = "lastName";
		protected static const JSON_PROP_AGE:String = "age";
		protected static const JSON_PROP_FOODS:String = "foods";
		protected static const JSON_PROP_PET:String = "pet";
		
		public var firstName:String;
		public var lastName:String;
		public var age:int;
		public var foods:Vector.<String>;
		public var pet:Pet;
		
		public function Person()
		{
		}
		
		public function toJSON(s:String):*
		{
			var json:Object = {};
			json[JSON_PROP_FIRST_NAME] = firstName;
			json[JSON_PROP_LAST_NAME] = lastName;
			json[JSON_PROP_AGE] = age;
			json[JSON_PROP_FOODS] = foods;
			json[JSON_PROP_PET] = pet;
			return json;
		}
		
		public function importJSON(json:Object):void
		{
			for(var key:String in json){
				if(key == JSON_PROP_FIRST_NAME && json[key] is String){
					//この辺でいろいろと値チェックとか
					// ....

					this.firstName = json[key];
					
				}else if(key == JSON_PROP_LAST_NAME && json[key] is String){
					this.lastName = json[key];
					
				}else if(key == JSON_PROP_AGE && json[key] is Number){
					this.age = json[key];
					
				}else if(key == JSON_PROP_FOODS && json[key] is Array){
					var foodsArr:Array = json[key];
					this.foods = new <String>[];
					for(var i:int = 0, len:int = foodsArr.length; i < len; i++){
						this.foods.push(foodsArr[i]);
					}
				}else if(key == JSON_PROP_PET && json[key] is Object){
					var parsedPet:Pet = new Pet();
					parsedPet.importJSON(json[key]);
					this.pet = parsedPet;
				}
			}
		}
	}
}

Pet

package
{
	public class Pet implements IJSONCompatible
	{
		protected static const JSON_PROP_NAME:String = "name";
		protected static const JSON_PROP_AGE:String = "age";
		
		public var name:String;
		public var age:int;
		
		public function Pet()
		{
			
		}
		
		public function toJSON(s:String):*
		{
			var json:Object = {};
			json[JSON_PROP_NAME] = this.name;
			json[JSON_PROP_AGE] = this.age;
			return json;
		}
		
		public function importJSON(json:Object):void
		{
			for(var key:String in json){
				if(key == JSON_PROP_NAME && json[key] is String){
					this.name = json[key];
					
				}else if(key == JSON_PROP_AGE && json[key] is Number){
					this.age = json[key];
				}
			}
		}
	}
}

importJSONするときにチェックをいくつかしてます。
もしユーザーが保存したJSONテキストファイルを直接触れる場合、不正な値に書き換えられて、それを取り込んだアプリ側が困ってしまうことになるかもしれないです。

なので、いまはプロパティ名と型だけチェックしているのですが、例えば

・文字列だったら不正な文字がはいっていないか、文字数は正常値かどうか
・数値だったら最大値、最小値に収まっているかどうか

とかの値チェックをしてあげた方がよいと思います。

で、これを使うクライアントのクラスです。

//出力テスト
			var sourcePerson:Person = new Person();
			sourcePerson.firstName = "たろう";
			sourcePerson.lastName = "田中";
			sourcePerson.age = 31;
			sourcePerson.foods = new <String>["バナナ", "りんご", "マンゴー"];
			
			var sourcePet:Pet = new Pet();
			sourcePet.name = "ハチ";
			sourcePet.age = 10;
			sourcePerson.pet = sourcePet;
			
			var jsonStr:String = JSON.stringify(sourcePerson);
			trace("json str = " + jsonStr);

//出力
//json str = {"age":31,"pet":{"age":10,"name":"ハチ"},"firstName":"たろう","lastName":"田中","foods":["バナナ","りんご","マンゴー"]}
			
//入力テスト
			var parsedObj:Object = JSON.parse(jsonStr);
			
			var parsedPerson:Person = new Person();
			parsedPerson.importJSON(parsedObj);
			trace(parsedPerson); //ここでデバッガー仕掛けて中身をカクニン

ファイルの読み書き

JSONの変換ができるようになったので、あとはテキストファイルの保存と読み取りです。
ファイルの読み書きはこんな感じです。

			//書き出し
			var writefs:FileStream = new FileStream();
			writefs.open(File.applicationStorageDirectory.resolvePath("person.json"), FileMode.WRITE);
			writefs.writeUTFBytes(jsonStr); //jsonStrはJSON文字列です
			writefs.close();
			
			//読みこみ
			var readfs:FileStream = new FileStream();
			readfs.open(File.applicationStorageDirectory.resolvePath("person.json"), FileMode.READ);
			var readJSONStr:String = readfs.readUTFBytes(readfs.bytesAvailable);
			readfs.close();
			trace("読み込んだよ: " + readJSONStr);

こんな感じでアプリでJSONデータを扱えるかなと。


自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る