2013年1月5日土曜日

Androidプログラム開発-ファイル入出力

プログラムを移植するのに、あと一つ乗り越えないといけない壁があります。「ファイル入出力」です。

計算結果をログとしてstorageに出力したいですし、各種設定データをファイルとして読み込む必要があります。またそれらは、Android端末をUSB接続したときに簡単にアクセスできる場所がいいです。
試しに従来のJavaプログラムで作成した簡単なログ書き込みのプログラムを移植してみようとしたら、「そんなクラスはない!」と怒られてしまいました。Android用のiostreamじゃなきゃだめだということが確認できたので(事前に予測はしてました)、ググってみるとどうしてもファイルエクスプローラのアプリ紹介のページにいってしまいます。キーワードを考えて、やっと見つけました。
ファイル出力の方ではFileOutputStreamを使い以下の様なメソッドだとか。

outputStreamObj=context.openFileOutput( )

ところでこのcontextなるインスタンスは何者?ページをよく読むと、Androidプログラムの本体のインスタンスらしく、これを使うと/data/data/(パッケージ名)以下のパスしか指定できないとか。ここ普通のファイルエクスプローラではPermissionがありませんといって、見ることすらできません。(jail breakして、root化すればいけますが、そもそもUSB接続して簡単に参照したいのでそれでは困ります。)
さらに調べると、普通のjava.ioパッケージでもできるとの情報がありました。これならフルパスでファイルを指定できますが、ことごとくPermission denyで怒られます。セキュリティがガチガチですね。
USB接続して簡単にアクセス、というのが目標なので/sdcard以下にファイルを作ろうとしたんですが、そもそもeclipseに”/sdcard”のパスを直接コードするんじゃありません、と注意される始末。調べてみると、以下のメソッドを使いAndroid端末に合わせたパスを取得しろとのこと。

String str = Environment.getExternalStorageDirectory().getPath();
writeFile(str+"/Documents/log.csv","abcdefg","UTF-8");

Environment自体はstaticで定義されていますから、当該パッケージをimportするだけでそのまま使えます。上記ではとりあえずDocuments以下にファイルを作成してみました。
さてこれでいいだろうと思ったら、まだPermissionがないと怒られます。再度、ググった結果当該パッケージのManifest.xmlに以下の記述が必要なのだとか。(デフォルトではファイルアクセス禁止のプログラムしか作れないんですか Orz)

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>


Manifest.xmlのどこに記述したらいいのかわからなかったので、そこはeclipseのUIにおまかせしました。(結果見ると、自前でタグ定義しているんでどこでもよさそうです。)

これでやっと準備ができたと思います。(移植しようと考えてるJavaプログラムのファイル入出力のモジュールをAndroid用に修正しないといけません)

追記:
ところで実際にAndroid端末(Nexus7を使ってます)をUSBでPCと接続し、先ほどプログラムで作成したファイルを見てみようとしたんですが、なんと見えません!Nexus7のファイルエクスプローラ・アプリでは確かにファイルが存在しいるんですが、PCではファイルが表示されません。同じディレクトリにある別のファイルはNexus7でもPCでも見えるんですが。。。
またまたググって、しかし今回はどんなキーワードで検索したらいいのか思いつきません。結構時間がかかりましたが、原因と思えるものが見つかりました。

・MTP(メディアデバイス)
Nexus7の設定みているとUSBストレージという名称じゃない別の名称のMTPで接続というのがあります。これは従来のUSBストレージだとUSBスティックのようにFATでファイルシステムを作り、それをPCから参照します。これって考えると結構危険です。Nexus7側のアプリが開いているファイルでもPCから修正できちゃうことになりますから。なのでMTPは一種のネットワークドライブのようにPCからは見せて、ファイルシステムとして認識しなくてもいいようにします。(Android3.1からこの機能がついたようです)
端末によっては従来のUSBストレージによる接続も残しているようですが、Nexus7では見当たりませんでした。(まあAndroidを主導しているGoogleとしては、新しい方式にして欲しいだろうし)

・マルチアカウント
最新のAndroid4.2.1からでしたか、マルチユーザーの機能が付加されました。当然、ファイルシステムだってその影響がでます。具体的には外部ドライブだろうが、各ユーザーが使えるエリアはユーザーアカウント毎に用意されています。具体的にいうと以下のような感じになるそうです。

/sdcard/0/Documents等

数字のところがユーザーに割り振られた番号で(UIDのようなものです)、各ユーザーごとに番号が振られます。つまりNexus7に異なるユーザーで使っていると、他人のユーザーの外部ストレージは見えません。(セキュリティ上のためもあります)更にいやらしいことに、上記の数字よりTopの"/sdcard"というのもAndroidの実装まかせで固定していないんだそうです。(いやこれは強制しようよ、Googleさん)それを回避して一つのアプリで複数の機種に対応するため、/sdcard/0までを取得するメソッド(getExternalStorageDirectory())が用意されたそうです。

さてここまで調べて、ファイルが見えなかった理由の推測ですが、Android4.0になってからでしたっけ、明示的なタスク管理のタスクマネージャーがなくなりました。そのため、試験的に作成したプログラムが停止していると思っても、実は裏でファイルハンドルをつかんで離さないから、PC側からは見えないんではなかろうかと。確実に確認するためにNexus7を再起動して、PCに接続すると無事プログラムが作成したファイルを見ることができました。(設定→アプリケーションで選択して強制終了してもいいと思います)


0 件のコメント:

コメントを投稿