Uri(android.net.Uri)と File(java.io.File) の変換

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 に関しては、別の機会にメモを書きたいと思う。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Time limit is exhausted. Please reload CAPTCHA.