Android でファイルの情報を扱う場合、Java の標準的なクラス java.io.Fileを利用する場合と、android.net.Uriを利用する場合がある。File クラスを利用する場合は、Android 上のディレクトリやファイルを直接指定する(※)。一方 Uri は java.net.URI と同様に RFC 2396で定義された URI 参照を表す。java.net.URI と異なり、Uri は入力チェックをほとんど行わないようだ。Uri のメソッドがスローする Exception をみると、NullPointerException、UnsupportedOperationException しかなかった。
※Android では、ファイル名は UTF-8のバイトシーケンスで OS とやりとりする。
他の Activity と連携しない、情報も取得しないというのであれば File だけで事足りるのだが、Intent 経由でデータを受け取る Intent.getData()メソッドは Uri が戻り値になっている。データを保存するときは File クラスを使っていたので、File と Uri の変換が必要になった。File から Uri の変換は簡単だが、Uri から File にするのは面倒だったのでメモとして残すことにした。
File から Uri への変換
File から Uri への変換は、Uri に static メソッドが用意されているので簡単だ。変換したい File のオブジェクトを fromFile(File)メソッドに渡すだけでよい。
File file = new File(...); Uri uri = Uri.fromFile(file);
Uri から File への変換
最初に書いていたコードは、以下のように単純なものだ。他の Activity からデータを受領するだけなので、必ずファイルだと思っていた。
Intent intent; // どこかから受け取った Intent Uri = intent.getData(); String path = uri.getPath(); File file = new File(path);
しかし Uri は RFC 2396形式の URI 参照で、常に実ファイルを指しているとは限らない。同様に RF2396形式の URI 参照であるjava.net.URIにサンプルが載っているので引用する。
不透明 URI は、スキーム固有部分がスラッシュ (「/」) で始まらない絶対 URI です。不透明 URI はそれ以上解析されません。不透明 URI の例を次に示します。
mailto:java-net@java.sun.com
news:comp.lang.java
urn:isbn:096139210x階層 URI は、スキーム固有部分がスラッシュで始まる絶対 URI、または相対 URI (スキームを指定しない URI) です。階層 URI の例を次に示します。
http://java.sun.com/j2se/1.3/
docs/guide/collections/designfaq.html#28
../../../demo/jfc/SwingSet2/src/SwingSet2.java
file:///~/calendar
※「不透明」は、opaque の訳。「スキーム」は scheme の訳(スキーマと表記されていることもある)。
Android で android.net.Uri を java.io.File に変換する場合、Uri のスキームを見なければならない。スキームが「file」であれば最初のコードで問題ないが、「content」の場合は、Content Provider から取得する必要がある。
Intent intent; // どこかから受け取った Intent Uri = intent.getData(); Context context = getContext(); String scheme = uri.getScheme(); String path = null; if ("file".equals(scheme)) { path = uri.getPath(); } else if("content".equals(scheme)) { ContentResolver contentResolver = context.getContentResolver(); Cursor cursor = contentResolver.query(uri, new String[] { MediaColumns.DATA }, null, null, null); if (cursor != null) { cursor.moveToFirst(); path = cursor.getString(0); cursor.close(); } } File file = null == path ? null : new File(path);
ContentResolver.quiry(Uri, String[], String, String[], String) メソッドの引数は、API の説明によれば、「Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder」となっている。uri は content スキームの URI、projection は検索する列を指定する。今回は指定していないが、selection はフィルターのための追加条件、selectionArgs は selection で指定したプレースホルダーに当てはめる値、sortOrder はソート順序だ。ContentResolver に関しては、別の機会にメモを書きたいと思う。