Androidのファイル入出力で結構悩んだのでそのメモ。

書き込み可能かどうか考える *

Androidでは、誰でも好きなパスに書き込みができるわけではありません!アプリの権限の許された部分のみに書き込みできます。書き込みができるのは、次のディレクトリです。

可能なパス

補足

/sdcard/xxx

SDカード

/data/data/パッケージ名/xxx

データフォルダ

ディレクトリとファイルの問題 *

ニアミスとして、test というファイルを書こうと頑張っていて、なぜか書けない・・・なぜだ~と悩んでいたら、test というフォルダが既にあったんです。間違っていたのは、以下のようなコード。

File f = new File("/sdcard/hoge/test.txt");
f.mkdirs(); // ←ここが間違い
// フォルダなので当然エラー!!
FileOutputStream fo = new FileOutputStream(f); 

この時に、f.canWrite() で調べても、true が返ってくるので、なぜだ?!と思っていたのですが、ぼーっとしていて、フォルダとファイルの区別がついていなかったというオチ。

assets ディレクトリのファイルは特別なメソッドを通して操作する *

Androidのリソースとしてファイルを埋め込んだ場合、つまり、assets ディレクトリの場合。単純に /android_assets/xxx のようなパスを書いてもファイルを取り出せません。AssetManager を使ってファイルをオープンする必要があります。以下、アセットからSDカードにファイルをコピーするメソッド。

private static int BUFFSIZE = 1024 * 16;
public static boolean copyAssetsFile(Activity app, String assetsName, String savepath) {
    FileOutputStream fo;
    InputStream inp;
    try {
        File f = new File(savepath);
        File parent = f.getParentFile();
        if (parent != null && parent.canWrite()) { parent.mkdirs(); }
        fo = new FileOutputStream(f);
    } catch (IOException e) {
        Log.e("myapp", "copyAssetsFile() savepath could not open:" + e.getMessage() + ",file=" + savepath);
        return false;
    }
    AssetManager am = app.getResources().getAssets();
    try {
        byte[] buf = new byte[BUFFSIZE];
        inp = am.open(assetsName);
        while (true) {
            int sz = inp.read(buf, 0, BUFFSIZE);
            if (sz <= 0) break;
            fo.write(buf, 0, sz);
        }
        fo.close();
        return true;
    }catch(IOException e) {
        Log.e("myapp", e.getMessage());
        return false;
    }
}

後は、単純にパスを書き間違えていたとか、そんな感じです。