Android
アプリ固有のストレージでのファイル操作
(API30以降)
2023.8.4 Coskx Lab
1 はじめに
Android11(R)API30以降ではファイル保存領域の扱いが厳格になっています。
大きく分けると次のようになっています。
- 内部ストレージ内のアプリ固有のディレクトリ
他のアプリからはアクセス出来ないディレクトリ
- 外部ストレージ内のアプリ固有のディレクトリ
他のアプリは通常アクセスできないが,特別に権限を持ったファイルマネージャアプリなどではアクセス可能なディレクトリ
- 共有ストレージ内のメディア用途のディレクトリ
メディア ファイル用で他のアプリもアクセスできるディレクトリ
- 共有ストレージ内の一般用途のディレクトリ
他のアプリからアクセスされることを前提としたディレクトリ
ここでは,次の2つについて説明します。
- 内部ストレージ内のアプリ固有のディレクトリ →3
- 外部ストレージ内のアプリ固有のディレクトリ →4
ここで扱わない「共有ストレージ内のディレクトリ(一般的なファイル)」については次を参照してください。
共有ストレージ
なお,本説明内容のテストプログラムをダウンロードできます。
MainActivity.javaとactivity_main.xmlが入っています。(API24以上でテスト済)
ダウンロード
ストレージ詳細
Android デベロッパーのAndroid 11(API レベル 30)の説明では,内部ストレージ・外部ストレージは論理的な区別で,アプリの視点からは,自分しかアクセスできない領域が内部ストレージ,そうでない領域が外部ストレージになります。
(https://developer.android.com/about/versions/11/privacy/storage)
(内部・外部ストレージというのは,物理的な内部・外部という意味ではないので本体内ストレージとSDカードを区別しているわけではありません。Android 11の前にはこのような区別の表現も使われていたため,注意が必要です。)
共有ストレージは外部ストレージ内にあります。(SDカードも外部ストレージに含まれます。)
〇内部ストレージは,AndroidDevice(スマホなど)のファイルマネージャアプリで見ることはできません。
〇外部ストレージはファイルマネージャアプリで見ることが出来ますが,外部ストレージ内のアプリ固有のディレクトリは見ることが出来ません。
しかし,ファイルマネージャアプリによっては権限を設定すれば見ることができます。
例えばアプリ[Files by Google]では見ることはできませんが,[File Manager Plus]のアプリ[ファイルマネージャ]では見ることができます。
Android StudioのDevice File Explorerを使うと,内部ストレージ内のアプリ固有のディレクトリ,外部ストレージ内のアプリ固有のディレクトリもすべて見ることができます。
使いかた
- WindowsPCとAndroid DeviceをUSBケーブルで接続する。
- Android Studioで上部メニューから View > Tool Windows > Device File Explorer で起動する。
見え方(Android DeviceでのOS実装によるので,多少の違いはあると思います。)
- アプリ固有の内部ストレージ: data/data/[applicationId]/files/ に見える
- アプリ固有の外部ストレージ: storage/self/primary/android/data/[applicationId]/files/Documents/ に見える。
(ただしstorage/self/primary/はstorage/emulated/0へのリンク)
* applicationId は build.gradle(:app)内のandroid{ defaultConfig{ applicationId に定義されている。
(namespaceと一致していることが多いが,一致しているとは限らない)
Android Deviceのディレクトリ(フォルダ)構造
SDカードが実装されていないDeviceの例
storage/self/primaryのところはstorage/emulated/0と表示されることもあります。
その他
- AndroidDeviceのファイルマネージャアプリではstorage/self/primary/(storage/emulated/0)が見えている
- storage/self/primary/(storage/emulated/0)には,Android,DCIM,Download,Movies,Music,Picturesなどがある。
- WindowsPCのExplorerでAndroid DeviceをUSBメモリとして見ているときは,storage/self/primary/(storage/emulated/0)が見える。アプリ固有の外部メモリ領域も見える。
2 使用環境
- Windows 10 64-bit
- Android Studio Flamingo 2022.2.1 patch2 Build #AI-222.4459.24.2221.10121639, built on May 12, 2023
- java
- Build Target 33 (24以降で動作検証済)
3 内部ストレージ内のアプリ固有のディレクトリ
内部ストレージ内のアプリ固有のディレクトリへのファイルの書き込み,読み込みをします。
内部ストレージ内のアプリ固有のディレクトリ名を取得すれば,任意のファイル名で作業ができます。
内部ストレージ内のアプリ固有のディレクトリは
メソッド File getFilesDir()
で得ることができます。
内部ストレージ内のアプリ固有のディレクトリ名を文字列として確認するためには,
String internalstorage = String.valueOf( this.getFilesDir() );
で得ることができます。(MainActivity内)
Device File Explorerで見るときとは異なり,実際は次のように得られました。
/data/user/0/[applicationId]/files
3.1 内部ストレージ内のアプリ固有のディレクトリへのファイル書き込み
内部ストレージ内のアプリ固有のディレクトリへのファイル書き込みの例を示します。
- FileWriter()の第2引数は上書き又は追記を指示します。
- true:追記 ファイルが既にあれば,ファイルの末尾に追加します。無ければ新規ファイルに書き込みます。
- false:上書き 新規ファイルに書き込みます。ファイルが既にあれば,それを消してから書き込みます。
String internalfname = "intsample.txt";
String internaltext = "Hello,\nTHis is a internalstorage sample text.\n";
File file1;
String message;
file1 = new File(this.getFilesDir(), internalfname);
try (FileWriter writer = new FileWriter(file1,true)) {
writer.write(internaltext);
writer.flush();
writer.close();
message = "File saved.";
} catch (IOException e) {
message = e.getMessage();
e.printStackTrace();
}
Log.i(TAG, message);
3.2 内部ストレージ内のアプリ固有のディレクトリからのファイル読み込み
内部ストレージ内のアプリ固有のディレクトリからのファイル読み込みの例を示します。
String internalfname = "intsample.txt";
File file1;
String message;
StringBuilder text = new StringBuilder();
file1 = new File(this.getFilesDir(), internalfname);
try (BufferedReader reader = new BufferedReader(new FileReader(file1))) {
String lineBuffer;
lineBuffer = reader.readLine();
while (lineBuffer != null) {
text.append(lineBuffer).append("\n");
lineBuffer = reader.readLine();
}
message = "text read = [\n" + text + "]";
} catch (IOException e) {
message = e.getMessage();
e.printStackTrace();
}
Log.i(TAG, message);
3.3 内部ストレージ内のアプリ固有のディレクトリ内のファイル一覧を得る
内部ストレージ内のアプリ固有のディレクトリ内のファイル一覧を得る例を示します。
File dir;
File[] files;
String message;
StringBuilder text = new StringBuilder("\n");
dir = this.getFilesDir();
files = dir.listFiles();
if (files != null) {
for (File file : files) {
text.append(file.getName()).append("\n");
}
}
message = "listed filenames = [" + text.toString() + "]";
Log.i(TAG, message);
3.4 内部ストレージ内のアプリ固有のディレクトリ内のファイルを全消去する
内部ストレージ内のアプリ固有のディレクトリ内のファイルを全消去する例を示します。
File dir;
File[] files;
String message;
StringBuilder text = new StringBuilder("\n");
dir = this.getFilesDir();
files = dir.listFiles();
if (files != null) {
for (File file : files) {
text.append(file.getName()).append("\n");
file.delete();
}
}
message = "deleted files = [" + text.toString() + "]";
Log.i(TAG, message);
4 外部ストレージ内のアプリ固有のディレクトリ
外部ストレージ内のアプリ固有のディレクトリへのファイルの書き込み,読み込みをします。
外部ストレージ内のアプリ固有のディレクトリ名を取得すれば,任意のファイル名で作業ができます。
外部ストレージ内のアプリ固有のディレクトリは
メソッド File getExternalFilesDir( Environment.DIRECTORY_DOCUMENTS )
で得ることができます。
外部ストレージ内のアプリ固有のディレクトリ名を文字列として確認するためには,
String externalstorage = String.valueOf( this.getExternalFilesDir( Environment.DIRECTORY_DOCUMENTS ) );
で得ることができます。(MainActivity内) 実際には次のように得られました。
/storage/emulated/0/Android/data/ [applicationId] /files/Documents
補足
File getExternalFilesDir( Environment.DIRECTORY_DOCUMENTS ) の代わりに
File getExternalFilesDir( Environment.DIRECTORY_PICTURES )
にすると
/storage/emulated/0/Android/data/ [applicationId] /files/Pictures
になります。
Environment.DIRECTORY_xxxxxxx にはいろいろな設定があります。
4.1 外部ストレージ内のアプリ固有のディレクトリへのファイル書き込み
外部ストレージ内のアプリ固有のディレクトリへのファイル書き込みの例を示します。
FileWriter()の第2引数は上書き又は追記を指示します。
true:追記 false:上書き
String externalfname = "extsample.txt";
String externaltext = "Hello,\nTHis is a externalstorage sample text.\n";
File dir;
File file1;
String message;
dir = this.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
file1 = new File(dir, externalfname);
Log.i(TAG,"file name = " + String.valueOf(file1));
boolean done = false;
try (FileWriter writer = new FileWriter(file1,true)) {
writer.write(externaltext);
writer.flush();
writer.close();
done = true;
message = "File saved.";
} catch (IOException e) {
message = e.getMessage();
e.printStackTrace();
}
Log.i(TAG, message);
4.2 外部ストレージ内のアプリ固有のディレクトリからのファイル読み込み
外部ストレージ内のアプリ固有のディレクトリからのファイル読み込みの例を示します。
String externalfname = "extsample.txt";
File dir;
File file1;
String message;
StringBuilder text = new StringBuilder();
dir = this.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
file1 = new File(dir, externalfname);
try (BufferedReader reader = new BufferedReader(new FileReader(file1))) {
String lineBuffer;
lineBuffer = reader.readLine();
while (lineBuffer != null) {
text.append(lineBuffer).append("\n");
lineBuffer = reader.readLine();
}
message = "text read = [\n" + text + "]";
} catch (IOException e) {
message = e.getMessage();
e.printStackTrace();
}
Log.i(TAG, message);
4.3 外部ストレージ内のアプリ固有のディレクトリ内のファイル一覧を得る
外部ストレージ内のアプリ固有のディレクトリ内のファイル一覧を得る例を示します。
File dir;
File[] files;
String message;
StringBuilder text = new StringBuilder("\n");
dir = this.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
files = dir.listFiles();
if (files != null) {
for (File file : files) {
text.append(file.getName()).append("\n");
}
}
message = "listed filenames = [" + text.toString() + "]";
Log.i(TAG, message);
4.4 外部ストレージ内のアプリ固有のディレクトリ内のファイルを全消去する
外部ストレージ内のアプリ固有のディレクトリ内のファイルを全消去する例を示します。
File dir;
File[] files;
String message;
StringBuilder text = new StringBuilder("\n");
dir = this.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
files = dir.listFiles();
if (files != null) {
for (File file : files) {
text.append(file.getName()).append("\n");
file.delete();
}
}
message = "deleted files = [" + text.toString() + "]";
Log.i(TAG, message);
5 補足
- 内部部ストレージ内のアプリ固有のディレクトリ,及び外部ストレージ内のアプリ固有のディレクトリ操作について権限付与は不要です。(AndroidManifest.xmlへの権限記載,権限取得操作はいらない)
-
これまで,API28以前におけるファイル操作では,書き込みや消去の直後に,MediaScannerServiceに登録しないとOSへの反映が出来なかったのですが,それはすべて不要になりました。
- アプリを消去すると,アプリ固有の内部メモリ領域とアプリ固有の外部メモリ領域は両方ともに消去されます。
6 まとめ
内部ストレージ内のアプリ固有のディレクトリ,および外部ストレージ内のアプリ固有のディレクトリで,それぞれについてファイル操作について示しました。
内部ストレージ内のアプリ固有のディレクトリでは,getFilesDir()で対象ディレクトリを得ることができます。
外部ストレージ内のアプリ固有のディレクトリでは,getExternalFilesDir( Environment.DIRECTORY_DOCUMENTS )で対象ディレクトリを得ることができます。
- ファイル書き込み(上書き,追記)
- ファイル読み込み
- ファイル一覧
- ファイル削除