ZipFile ~画像サイズが大きいと読み込み失敗

 先日のZipから画像を読み込む method に不具合があった。
 どうもBitmapFactory の時点で、読み込みミスをしているようす…。

 調べてみると、同様の症状に行き着いた。
http://groups.google.com/group/android-group-japan/browse_thread/thread/197c76b8fb3a8cc6?fwc=1
 どうやら、画像のデータサイズが大きいと、InputStream が読み込みミスをするらしい。
 回避するには、一度どこかに解凍してから、読み込むしかなさそう。

※.キャッシュファイルの保存
https://sites.google.com/a/techdoctranslator.com/jp/android/guide/data-storage

どのくらいだと大きい?

 素朴な疑問。
 サイズが大きいって、どのくらいだと大きいの? (?_?)

 読み込もうとしたのは、800×600のJPG。
 先日の試作アプリでは問題なかったものなんだ。
 じゃ、なにがちがうのかといえば、アプリ。
 不具合が出たのは、作ってるノベルアプリに組み込んでからなんだ。
 だから最初はノベルアプリを疑ったんだけど、そうじゃなさそうなのは前記のとおり。
 ではナニが制約になってるのかというと、たぶんヒープなんじゃないかと思う。

 試作アプリはZIP関係のClass しかないような状態で、ヒープに余裕がある。
 一方、ノベルアプリは色々と組み込んでいるから、ヒープに余裕があまりない。

 どのくらいだと”大きすぎる”かは、一概にいえないんじゃないかな?
 そういうワケで。
 直接メモリーに展開するのは、避けた方がよさそう。
 ”小さい”と思っていても、ヒープからすると「すごく大きいです…」になるかもしれないから。(w

by the way…

 原因を調べている途中で、BitmapFactory.Options なるものを見かけたよ。
 これを使うと、解像度や色数、サイズなんかを指定して、読み込めるらしい。
 GIFやPNG、サムネールなんかにはよさげなオプションだね。

※.コチラのページが詳しいです。
http://d.hatena.ne.jp/hyoromo/20101001/1285943744

Posted in File, 読み込み. Tags: , , , . ZipFile ~画像サイズが大きいと読み込み失敗 はコメントを受け付けていません。 »

ZipFile と ZipEntry ~Androidでzipを解凍する

 いわゆるアドベンチャー・ゲームみたいに、複数のデータファイルを扱う場合、それらをひとつのファイルにまとめることがほとんどだよね。
 その理由は、機密性が第一なのかな?
 でも配布を考えた場合、ひとつにまとまっていた方が都合いいんだ。
 まず、コピーが早い。
 ファイルの取りこぼしがない。
 それと一概にはいえないけど、通信パケットを節約できる。

 で、ひとつにまとめるには、どうしたらいいか?
 色々と方法はあるけど、オイラはzipを使うことにしている。
 なぜかといえば、まとめるツールは作らなくていいし、取り出すルーチンも簡単ですむから。

 というワケで、zipからデータを取り出すmethod を作ってみたよ。

ZipFile と ZipEntry

 zip を扱うのに、使うclass は以下の2つ。

●ZipFile
http://developer.android.com/reference/java/util/zip/ZipFile.html

●ZipEntry
http://developer.android.com/reference/java/util/zip/ZipEntry.html

 ZipFile は、そのままZIP を抽象化したもの。
 ZipEntry は、ZIPの中のファイルを抽象化したもの。

 method を眺めると、ZipEntry と Fileクラス はなんか似ている。
 たぶん、「ZipFile はHD、ZipEntry はファイル」と見立ててるんだろうね。
 取り出すときもInputStream を使うから、ファイル操作と手順はそう変わらなそう。

 ちなみに、ZipInputStream というclass もある。
 今回は使わなかったけど、役割はZipFile と同じみたいだ。
 おそらく、ネットからZIPを取得した時、メモリー上にZIPがある時、なんかに使うんだろね。

ファイル一覧を取得する

 まず、中のファイル一覧を取得してみた。
 下記method は、ZIPのパスを指定すると、中のファイル一覧をString配列として返すよ。

	public int err = 0;	// エラーがあったか? // -1 : エラー有り | other : エラーなし

	public String[] getList( String zipPath ){
		err = 0;
		String[] result = null;
		//--

		try{
			ZipFile zipFile = new ZipFile( zipPath );
			
			List<String> list = new ArrayList<String>();
			Enumeration<? extends ZipEntry>	enu = zipFile.entries();
			while( enu.hasMoreElements() ){
				ZipEntry entry = enu.nextElement();
				//--
				list.add( entry.getName() );
			}
			zipFile.close();
			
			result = (String[])list.toArray(new String[0]);
		}catch( Exception ex ){
			err = -1;
			Log.d( "Err", "// ZipIO : getList err... //" );
		}

		//--
		return result;
	}

 まず、ZIPのパスから、ZipFile オブジェクトを生成する。

 そして、entries() で、Enumeration を取得する。
 このEnumeration は、中のファイル、──つまりZipEntry の塊みたいなモンだと思っていい。
 Enumeration のnextElement() を使うと、順繰りにZipEntry を取り出せるんだ。

 で、取り出したZipEntry にgetName() をして、ファイル名を取得している。
 取得したファイル名は、いったんList オブジェクトに格納するよ。
 List オブジェクトは配列と似たようなものだけど、要素数を増やすことができるんだ。
 お陰でファイルの総数がわからなくても、配列を作ることができる。
 そして、ファイル名の格納が終わったら、List をtoArray()でString配列に変換するんだ。

 以上で、ファイル一覧を取得できた。
 応用として、getName() をgetSize() にすると、容量一覧が取得できるね。
 ※.getSize() は、long を返します。

 注意点は、ZipFile のclose。
 最後にclose してやらないと、メモリーリークする可能性があるから注意。

文字バケ

 一覧を取得できたので、画面に表示してみた。

文字バケ

 …と。なんかバケてるね。(^_^;
 Windowsで作ったZIPなので、ファイル名がShift-JISなのかもしれない。
 それじゃ、Macで作ったZIPならバケない…?

文字バケ

 …見事にバケてるよ。(w

 これはたぶん、Javaレベルの問題。
 1バイト文字専用で、2バイトやUTF-8に対応していないんだね。
 バケ方のちがいからすると、そんな感じ。

 2バイト文字に対応するには、取得したファイル名をデコードしてやらないといけないんだね。
 まぁ、解凍には支障ないんで、今回はパスしておくよ。

ファイルを解凍してみた

 次に、ファイルを指定して、解凍してみた。

 下記method で、指定したファイルを解凍するよ。
 手順は、ファイルのコピーとそう変わらないね。

 引数は、
  ZIPのパスを指定
  解凍するファイル名
  解凍先(Path付ファイル名)

	public int err = 0;	// エラーがあったか? // -1 : エラー有り | other : エラーなし

	public void meltFile( String zipPath, String file, String outFile ){
		err = 0;
		try{
			ZipFile zipFile = new ZipFile( zipPath );
			ZipEntry entry = zipFile.getEntry( file );
			InputStream is = zipFile.getInputStream( entry );
			
			OutputStream os = new FileOutputStream( outFile );

			byte[] buffer = new byte[ 1024*4 ];	// 1024*4 = DEFAULT BUFFER SIZE
			int r = 0;
			while( -1 != ( r = is.read(buffer)) ){
				os.write( buffer, 0, r );
			}

			os.close();
			is.close();
			zipFile.close();
		}catch( Exception ex ){
			err = -1;
			Log.d( "Err", "// ZipIO : meltFile err... //" );
		}

		//--
	}

 ディレクトリの中にファイルがある場合、解凍するファイル名をPath付にしてやる。
 こんな感じ。

	dir/char.gif

 ただし、2バイトの場合、↓ではダメ。

	新しいフォルダ/char.gif

※.UTF-8 のZIPなら解凍できるかも…?

 たぶん、「1バイト化け」した状態で指定してやれば解凍できるんじゃないかな?
 もしくはファイル名以外の方法で、ZipEntry を取得してやればいいと思う。

 ちなみに上記サンプルでは、解凍先にディレクトリは作られない。
 必要があるなら、別途つけくわえてね。

画像データを取得してみた

 データとして取り出すにはどうしたらいいんだろ?
 ここにひとつ問題があるんだ。

 一覧取得でちょっと触れたけど、ファイルサイズの単位は、long なんだ。
 これではbyte配列自体が作れない。
 int サイズに限定すればできるけど、そういう制限はかけたくない。

 となると、InputStream から直接、目的のデータにすることになりそう。
 というワケで。
 画像データ(Bitmap)として取り出すmethod を作ってみた。

	public int err = 0;	// エラーがあったか? // -1 : エラー有り | other : エラーなし

	public Bitmap meltBitmap( String zipPath, String file ){
		err = 0;
		Bitmap result = null;
		//--

		try{
			ZipFile zipFile = new ZipFile( zipPath );
			ZipEntry entry = zipFile.getEntry( file );
			InputStream is = zipFile.getInputStream( entry );
			result = BitmapFactory.decodeStream( is );

			is.close();
			zipFile.close();
		}catch( Exception ex ){
			err = -1;
			Log.d( "Err", "// ZipIO : meltBitmap err... //" );
		}

		//--
		return result;
	}

 BitmapFactory で、InputStream からBitmap にしている。
 この方法は、ネットから画像データを取得するのと同じ方法。

 Drawable で取り出す時には、

	Drawable.createFromStream

 を使えばいいよ。

 取得した画像データをImageView で表示してみた。
 問題なし。(^_^)
※.画像サイズが大きいと、失敗することがあるらしい。
 詳しいくは…

「ZipFile ~画像サイズが大きいと読み込み失敗」

解凍表示

by the way…

 個人的に困ったのは、RandomAccessFile が使えないことだね。
 ヘッダー位置の取得方法がないから、部分的に読み込むことができない。
 できないワケじゃないけど、イロイロと面倒なんだな、これが。(^_^;
 一度テンポラリーに、ファイルとして解凍するのがいいのかな…。

Posted in File, 読み込み. Tags: , , , , , , , . ZipFile と ZipEntry ~Androidでzipを解凍する はコメントを受け付けていません。 »

RandomAccessFile ~Shif-JISで読み込む

 RandomAccessFile では、文字コードの指定はできない。
 Shift-JISも扱いたいので、別項のソースに手を加えてみたよ。

	public long head_pos = 0;	//現在のseekヘッド位置

	public String readline_RA( String path, long readPos, String code ) {
//	Log.d("TEST", "readline_RA : "+path );

		String result = "";
		//--

		try{
			File file = new File( path );
			RandomAccessFile ra = new RandomAccessFile( file, "r" );
			ra.seek( readPos );

			String str = ra.readLine();
			if ( str!= null ){
				result = str;
			//	}else{
				//	result = "";
				//	Log.d("Err", "// readline_RA : read is null //" );
			}
			head_pos = ra.getFilePointer();

			//
			if ( code != "UTF-8" ){
				// 改行コード判定
				//	CR : 0x0D : \r
				//	LF : 0x0A : \n
				//	UNIX = LF : Mac = CR : DOS = CR+LF

				byte[] buffer = new byte[ 2 ];	// 行末2バイトを読み込む
				ra.seek( head_pos -2 );
				ra.read(buffer);
				long RT = 1;
				if ( ( buffer[0] == 0x0D )&&( buffer[1] == 0x0A ) ){	//DOS
					RT = 2;
				}
				//--

				ra.seek( readPos );
				buffer = new byte[ (int)( head_pos -RT -readPos ) ];	// 読み込む量
				int r = ra.read(buffer);
				if ( -1 != r ){
					result = new String( buffer, code );
				}
			}
			//--

			ra.close();
		}catch( Exception e ){
			Log.d("Err", "// readline_RA : read ERR //" );
		}
		
		//--
		return result;
	}

仕組み

 手を加えた部分のは、23行~46行。

	1. readLine で読み込んだ範囲を、byte 配列で読み込み直す。
	2. byte 配列を文字コードを指定して、String に変換。

 readLine のデータを直接変換するのがシンプルなんだけど…。
 そのデータは、すでにUTF-8のためのbyte を差し挟まれちゃってる。
 そんなbyte 配列をプレーンな状態にするより、もう一度読み込んだ方が、結果的にシンプルなんだよね。
 直接変換するようなものがあるのかもしれないけど。

 だもんで、readLine は「一行の範囲を調べる」だけになってる。(^_^;

読み込み範囲

 最初の位置からgetFilePointer までを読み込むと、改行コードがbyte 配列に含まれてしまう。
 これをそのままTextView へ表示すると、不明文字のトウフが表示されちゃう。
 それは都合がわるいので、改行コードを調べて、読み込み範囲を補正する必要がある。(30~36行目)
 調べた値は long RT に格納し、読み込み範囲の補正に使っている(39行目)

文字コード指定

 指定した文字コードで変換するのは、難しくない。
 byte から、文字コードを指定して、String を作るだけ。(43行目)

	result = new String( buffer, code );

by the way…

 引数 code は、String で文字コードを指定することにしている。
 シフトJISなら、”Shift_JIS”。
 試してないけど、EUC-JPにも対応してるハズ。

Posted in File, 読み込み. Tags: , , . RandomAccessFile ~Shif-JISで読み込む はコメントを受け付けていません。 »

RandomAccessFile ~ファイルの読み込み

 ファイルを扱うclass は色々あるね。
 今回はRandomAccessFile を使ってみたよ。

RandomAccessFile の利点

 RandomAccessFile を使うと、読み込み位置なんかを指定できるんだ。
 これはゲームの再開なんかに、とても都合がいい。

RandomAccessFile での読み込み

 下記サンプルでは、テキスト・ファイルを一行読み込みしている。

	public long head_pos = 0;	//現在のseekヘッド位置

	public String readline_RA( String path, long readPos, String code ) {
//	Log.d("TEST", "readline_RA : "+path );

		String result = "";
		//--

		try{
			File file = new File( path );
			RandomAccessFile ra = new RandomAccessFile( file, "r" );
			ra.seek( readPos );

			String str = ra.readLine();
			if ( str!= null ){
				result = str;
			//	}else{
				//	result = "";
				//	Log.d("Err", "// readline_RA : read is null //" );
			}
			head_pos = ra.getFilePointer();

			ra.close();
		}catch( Exception e ){
			Log.d("Err", "// readline_RA : read ERR //" );
		}
		
		//--
		return result;
	}

モード設定

 RandomAccessFile は書き込み、読み込みで、別class になっていない。
 そのため、オブジェクト生成時に、モードを設定する必要がある。
 下記では、読み込み専用として生成している。

	new RandomAccessFile( file, "r" );

位置設定

 書き込み位置、読み込み位置の設定は、seek method を使う。
 値はlong で指定する。

	seek( readPos );

位置の取得

 書き込み位置、読み込み位置の取得は、getFilePointer method を使う。
 値はlong 。

	getFilePointer();

by the way…

 RandomAccessFile では、文字コードの指定はできない。
 そのためテキストファイルは、デフォルト・コード(UTF-8)で扱われてしまう。
 Shift-JISを扱うには、別途自前で直す必要がある。
 コレに関しては、別項・

Shif-JISで読み込む
にて。

Posted in File, 読み込み. Tags: , . RandomAccessFile ~ファイルの読み込み はコメントを受け付けていません。 »

リソースからのファイルコピー

 エミュレータにテスト・ファイルを送りたい。
 WebからDownLoadする、コンソールからwgetする…?
 いろいろやり方はあるけど、リソースからコピーできると便利。
 「デモファイルのインストール」なんて機能にもなるしね。

 やり方はシンプルなコピーとそう変わりがない。
 リソースのpathを取得するには、Resources class を使うのだが。
 このResources からは、InputStream しか生成できない。
 そのため、FileChannel は使えないんだ。

 下記サンプルでは、SDカードのルートにファイルをコピーしている。

	public void cpResTo_SD( Context context, int res_id, String fName ) {
		
		// Copy先の取得
		File cpFile = new File( Environment.getExternalStorageDirectory().getPath()+"/" +fName );
//	Log.d( "TEST", "copy to :" +cpFile.getPath() );
	
		// exec copy
		try{
			
			Resources res = context.getResources();
			
			InputStream is = res.openRawResource( res_id );
			OutputStream os = new FileOutputStream( cpFile );

			byte[] buffer = new byte[ 1024*4 ];	// 1024*4 = DEFAULT BUFFER SIZE
			int r = 0;
			while( -1 != ( r = is.read(buffer)) ){
				os.write( buffer, 0, r );
			}

			is.close();
			os.close();
			
		}catch( Exception ex ){
			Log.d( "TEST", "/res -> copy error..." );
		}
		//--
	}

 DEFAULT BUFFER SIZE が 1024*4 となっているのは、ファイルの最小サイズが4kだから。
 これより大きくても、小さくても問題ないけど、4kにしておくのが一番、効率がいい。

 注意点としては、リソースの場所があげられる。
 たとえばテキスト・ファイルなんかを、/values に格納するとeclipse でエラーとなる。
 /raw なんかを作り、そこに格納しておく必要がある。

Posted in File, コピー. Tags: , , . リソースからのファイルコピー はコメントを受け付けていません。 »

SharedPreferencesモドキを作ろう

 XmlSerializer なんかをイジって、xml 関係がだいたい飲み込めた。
 しかし、データ・フォーマットを考えるのはめんどくさい。読み込み部が専用になるのも、なんかアレよね。
 読み込みは遅いが、やっぱ融通の効くSharedPreferences は便利だ。
 しかし、SharedPreferences は外部ファイルを読み込めない…。
 なら作ってしまえ、というワケ。
 どうせint とString しか使う予定もないし。
 そんなに面倒でもないだろう。

package com.migimaki.android;

import android.content.Context;

import java.io.FileInputStream;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;

import android.util.Log;


/*
 * Preferences Reader クラス
 * 
 */
public class PrefReader {

	private Context context;
	public String fPath = "/";

//====================
//初期化
//====================
	/**
	 * コンストラクタ
	 */
	public PrefReader( Context c, String fPath ){
		context = c;
		this.fPath = fPath;
		//--
	}


//====================
// read method
//====================

	////////////
	/// Read Int
	public int getInt( String key, int default_i ){

		int result = default_i;
		//--

		try{
			FileInputStream is = new FileInputStream( fPath );
			XmlPullParser xmlPullParser = Xml.newPullParser();
			xmlPullParser.setInput( is, "UTF-8" );

			
			int i = xmlPullParser.getEventType();
			do{
				if( i == XmlPullParser.START_TAG 
						&& xmlPullParser.getName().equals( "int" )
							&& xmlPullParser.getAttributeValue( null, "name" ).equals( key )
					){

						result = Integer.parseInt( xmlPullParser.getAttributeValue( null, "value" ) );
						break;
				}
				i = xmlPullParser.next();
			}while ( i != XmlPullParser.END_DOCUMENT );

			is.close();

		}catch( Exception ex ){
			Log.d( "Err", "PrefReader : getInt" );
		}
		//--
	//	Log.d( "TEST", "PrefReader " +key +":" +result );
		return result;
	}
	///==
	
	////////////
	/// Read String
	public String getString( String key, String default_s ){

		String result = default_s;
		//--

		try{
			FileInputStream is = new FileInputStream( fPath );
			XmlPullParser xmlPullParser = Xml.newPullParser();
			xmlPullParser.setInput( is, "UTF-8" );

			
			int i = xmlPullParser.getEventType();
			do{				
				if( i == XmlPullParser.START_TAG 
						&& xmlPullParser.getName().equals( "string" )
							&& xmlPullParser.getAttributeValue( null, "name" ).equals( key )
					){

						result = xmlPullParser.nextText();
						break;
				}
				i = xmlPullParser.next();
			}while ( i != XmlPullParser.END_DOCUMENT );

			is.close();
			
		}catch( Exception ex ){
			Log.d( "Err", "PrefReader : getString" );
		}
		//--
	//	Log.d( "TEST", "PrefReader " +key +":" +result );
		return result;
	}
	///==
	
}

 できた。int とString だけだけど。(w

 各method でFileInputStream を設定しているのは、そうしないと読み込み位置が保持されてしまうため。

 SharedPreferences には、int とString の他に、boolean, float などなどがある。
 それらはおそらく、int とほぼ変わりがないだろうと思う。
 必要になったら、作るとしよう。

Posted in File, XML. Tags: , . SharedPreferencesモドキを作ろう はコメントを受け付けていません。 »

任意のXMLファイルの作成

 Androidアプリから、任意フォーマットのxmlを作成してみた。
 使用するのは、XmlSerializer

XmlSerializer って?

 XMLの作成には、XmlSerializerを使用しなくても行える。
 しかし、XML規格に沿って作成するには、それなりの知識も必要だし、ヘッダー等を整備するのも面倒くさい。
 XmlSerializer はそこらへんの面倒を引き受けて、XML の編集を行えるものらしい。
 また、書き込みの他に、読み込みmethod も用意されているようだ。

 ここでは書き込みのみXmlSerializer で行い、読み込みはXmlPullParser で行った。

XMLの書き出し

 書き出す内容は、以下の内容とすることにした。

	<xml? …>
	<gdat id="1">
	<Int>
	0
	</Int>
	<key>
	Kanon
	</key>
	</gdat>

 ※.xmlヘッダーは面倒なので略している。

 ソースでは以下のようになる。

//====================
// save method
//====================

	public void save( String fPath ){

		int i = 0;
		String key = "Kanon";
		//--
		
		XmlSerializer serializer = Xml.newSerializer();
		try {
			FileOutputStream os = new FileOutputStream( fPath );
			serializer.setOutput( os, "UTF-8" );
			
			serializer.startDocument("UTF-8", true);	// ヘッダー

			//<gdat id="1">
			serializer.startTag("", "gdat");
			serializer.attribute("", "id", "1" );
			//--

			//
				serializer.startTag("", "Int");	//<Int>
					serializer.text( ""+i );
				serializer.endTag("", "Int");	//</Int>
				
				serializer.startTag("", "key");	//<key>
					serializer.text( key );
				serializer.endTag("", "key");	//</key>
			//--

			serializer.endTag("", "gdat");	//</gdat>
			serializer.endDocument();	// フッター
			
			serializer.flush();	// 出力
			os.close();
		} catch (Exception e) {
		}
	}
	

 XmlSerializer は、それ自身でファイルにする能力はないようだ。
 そのため、FileOutputStream を出力先として指定している。( setOutput )
 また、出力先には、StringWriter 等も指定できる。

 編集自体は単純なので、ソースからわかるかと思う。

 編集が終われば、flush() で出力。
 FileOutputStream の出力先にファイルが作られる。

 なお、出力されたファイルを見てみると、改行コードが一切省かれていた。
 それでも機能するし、データも小さくなるからいいんだけど。(^_^;

XMLの読み込み

 読み込み方は、それぞれの効率性などから、色々とやり方が考えられる。
 サンプルでは、単純な順番読み込みをやってみた。

//====================
// load method
//====================

	public void load( String fPath ){
		
		try{
			FileInputStream is = new FileInputStream( fPath );

			XmlPullParser xmlPullParser = Xml.newPullParser();
			xmlPullParser.setInput( is, "UTF-8" );
			
			String buf_s = "";
			int buf_i = 0;
			
			Log.d( "TEST", "---- load start ----" );

			int i = xmlPullParser.next();
			if( i == XmlPullParser.START_TAG ){

				Log.d( "TEST", "Parser.getName : " +xmlPullParser.getName() );	// gat

				if ( xmlPullParser.getName().equals("gdat") ){
						buf_s = xmlPullParser.getAttributeValue( null, "id" );	// idの値
						buf_i = Integer.parseInt( buf_s );

						Log.d( "TEST", "" +buf_i );
				}
				xmlPullParser.next();

				if ( xmlPullParser.getName().equals("Int") ){	//Int
						buf_s = xmlPullParser.nextText();
						buf_i = Integer.parseInt( buf_s );

						Log.d( "TEST", "" +buf_i );
				}
				xmlPullParser.nextTag();	// -><END_TAG>
				xmlPullParser.nextTag();	// -><START_TAG>
			
				if ( xmlPullParser.getName().equals("key") ){	//key
						buf_s = xmlPullParser.nextText();

						Log.d( "TEST", "" +buf_s );
				}

			}
			Log.d( "TEST", "---- load over ----" );

			is.close();
		}catch( Exception ex ){
			Log.d( "Deb", "load error...(game data)" );
		}
		//--

	}

 非常にお莫迦なサンプルなので、実用的ではないね。(笑

 XmlPullParser は一行ごとに読み込みを行うようだ。
 next…とついているmethod は、「行送りをする」と考えていい。

	next()  … 一行送り。
	nextText()  … タグのtextを読み込み、一行送る。
	nextTag()  … 次の START_TAG か END_TAG まで送る

 getAttributeValue でタグのパラメータの値を取り出せる。
 パラメータ名の他にも、要素位置で読む方法もある。

	getAttributeValue(0)

 getName でタグの名前を取得。
 .equals で、文字列の比較を行える。
 .equals(“gdat”) だとしたら、==”gdat” と読み替えると理解しやすい。


 ここで取り上げた使用方法はほんの一例。
 他にも色々なmethod ややり方があるので、それぞれ調べてみてほしい。

Posted in File, XML. Tags: , , . 任意のXMLファイルの作成 はコメントを受け付けていません。 »

SharedPreferences ~セーブとロード

 ゲームなんかのプレイ・データを保存するには、SharedPreferences がラクでいいね。
 扱いも簡単だし、書き込み/読み込み順番とか気にしなくてもいい。

データの書き込み

 下記、例では指定したファイル(xmlName)に、3つのデータを書き込んでいる。

	// write
	public void write_xml( String xmlName ,int i, String key, String key2 ) {
		// MODE_WORLD_READABLE:他のアプリから読み取り可能
		// MODE_WORLD_WRITEABLE:他のアプリから書込み可能
		// MODE_PRIVATE:当アプリのみ使用可能

		SharedPreferences pref =
			getSharedPreferences( xmlName, MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE );
		Editor edit = pref.edit();
		
		edit.putInt( "score", i );
		edit.putString( "key", key );
		edit.putString( "key2", key2 );
		
		edit.commit();
	}

 まず、getSharedPreferences で、書き込むファイルを取得する。
 引数のxmlName には、xmlのファイル名を指定する。
 ただし、拡張子はつけない。
 pref.xml だとしたら、”pref” となる。

 次に、Editor を取得する。
 書き込みは、このEditor を介して行われる。

 書き込み内容の設定は、putInt などを使う。

	edit.putInt( "score", i );
		第一引数 : データ名
		第二引数 : データの値

 putIntの他にも、putString, putBoolean, putLong, putFloat が使える。

 設定をしたら、commit() でファイルに書き込む。

 ちなみに、commit() と同じ役割のapply() がある。
 違いは結果を返すか、返さないか。
 commit() だと boolean を返してくれるので、その値を調べれば成功したかがわかる。

データの読み込み

 下記、例では指定したファイル(xmlName)から、3つのデータを読み込んでいる。

	// Read
	public void read_xml( String xmlName ) {
		
		SharedPreferences pref =
			getSharedPreferences( xmlName, MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE );
		
		int i = pref.getInt( "score", 0 );
		String str = pref.getString( "key", "" );
		String str2 = pref.getString( "key2", "" );

	Log.d( "TEST", "read | score :" +i +" key:"+str +" key2:"+str2 );
	}

 手順は、書き込みの時とほぼ同じ。
 method の第二引数は、デフォルト値となる。
 なにかの原因で読み込めなかった場合、この値が返ってくる。

データの削除

 すべてのデータを削除するには、下記のようになる。

	// clear
	public void delete_data( String xmlName ) {
		SharedPreferences pref =
			getSharedPreferences( xmlName, MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE );
		Editor editor = pref.edit();
		editor.clear();	// all clear
		editor.commit();
		//--	
	}

 editor を取得して、clear()。その後、commit() を行う。
 commit() をしないと、反映されないので注意。
 データを指定して消す場合は、remove を使う。

	remove( String key );

 なお、全削除には、xmlファイルごと消してしまう方法もある。
 しかしその場合、すぐには反映されず、アプリの再起動が必要となるようだ。

Posted in File. Tags: , . SharedPreferences ~セーブとロード はコメントを受け付けていません。 »

ファイルのコピー

 ↓で、できるかと思ったら、できなかった…orz
 File file.renameTo( File newPath );

 じゃ、InputStream で読み込んで、OutputStream で書き出して、読み込んで書き出して…
 と、ループしなきゃならないのか。
 それは面倒…。
 なんて思ってたら、FileChannel を使うとよいらしい。

 下記、例では、アプリのプリファレンスをSDへコピーしている。

	public void cpTo_sd( ) {
		
		File file = new File( Environment.getDataDirectory().getPath()+"/data/" 
				+ this.getPackageName()
				+"/shared_prefs/pref.xml" );

		File cpFile = new File( Environment.getExternalStorageDirectory().getPath()
				+"/pref.xml" );

		try{
			FileChannel channel_In = new FileInputStream( file ).getChannel();
			FileChannel channel_Out = new FileOutputStream( cpFile ).getChannel();

			channel_In.transferTo( 0, channel_In.size(), channel_Out );

			channel_In.close();
			channel_Out.close();

		}catch( Exception ex ){
			Log.d( "TEST", "->sd : copy error..." );
		}
		//--
	}

 FileChannel には、他にもlock や読み込み位置の指定などがあり、色々と使えそうである。
http://developer.android.com/reference/java/nio/channels/FileChannel.html

Posted in File, コピー. Tags: , , , . ファイルのコピー はコメントを受け付けていません。 »