ストレージへアクセスする方法は、「扱うデータの種類」「アクセス先」「セキュリティの確保」などの要件により、最適なアクセス方法が存在するので、使い分けが必要です。
今回は「アクセスする方法」について、まとめます。
※環境:Android Studio Narwhal | 2025.1.1 Patch 1
目次
アクセスする方法
Androidアプリが、プログラムからストレージへアクセスする方法は3つあります。
- ・Java(Kotlin)/ Android API
- ・Media Store
- ・SAF(Storage Access Framework)
「扱うデータの種類」「アクセス先」「セキュリティの確保」などの要件により、最適なアクセス方法が存在するので、使い分けが必要です。
Java(Kotlin)/ Android API
Fileクラスを使ったJava(Kotlin)API標準の方法です。
保存先のパスはAndroid APIに組み込まれているので、関数を使って容易にFileオブジェクトを取得できます。
fun writeToFile_Basic(data: ByteArray, file: File) { try { file.outputStream().use { stream -> stream.write(data) } } catch (e: Exception) { Log.i(TAG, "[writeToFile] ${e}") } }
val _file = File(this@Activity.filesDir, _filename) // 保存先のパス writeToFile_Basic(_data, _file)
サンプルはアクセス方法を大まかに表現したものです。
※詳細は以下を参照
「内部ストレージにJava/Android APIでアクセス」
「外部ストレージ_プライマリにJava/Android APIでアクセス」
「外部ストレージ_セカンダリにJava/Android APIでアクセス」
Media Store
Content Resolver/Provider経由で、外部ストレージに保存されるメディアデータへ、アクセスする方法です。
メディアデータはデータベースで効率よく管理されています。
private val ContentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI fun Context.insertImage(data: ByteArray): Uri? { val _contentValues = ContentValues() val _mediaUri = contentResolver.insert(ContentUri, _contentValues) _mediaUri?.let { writeToUri_Resolver(data, _mediaUri) } return _mediaUri }
fun Context.writeToUri_Resolver(data: ByteArray, uri: Uri) { try { contentResolver.openOutputStream(uri, "w")?.use { outputStream -> outputStream.write(data) outputStream.flush() } } catch (e: Exception) { Log.i(TAG, "[writeToUri] ${e}") } }
_uri = insertImage(_data)
サンプルはアクセス方法を大まかに表現したものです。
※詳細は以下を参照
「」
SAF(Storage Access Framework)
Content Resolver/Provider経由で、外部ストレージに保存される全てのデータへ、アクセスする方法です。
アクセス対象のファイルは、Clientアプリが提供する標準のファイルピッカー(GUI)を使って、選択できます。
fun FileCreateIntent(filename: String) = // Clientアプリのインテント Intent(Intent.ACTION_CREATE_DOCUMENT).apply { addCategory(Intent.CATEGORY_OPENABLE) putExtra(Intent.EXTRA_TITLE, filename) type = "*/*" } fun ComponentActivity.CreateDocLauncher(callback: (Uri) -> Unit) = registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { result -> // Clientアプリの結果を処理 if(result.resultCode == RESULT_OK) { val _intent = result.data _intent?.let { val _uri = it.data _uri?.let { callback(it) } // ※Aを実行 } } else { Log.i(TAG, "ファイルが選べません !") } }
val _create = CreateDocLauncher { uri -> // Clientランチャーの作成 writeToUri_Resolver(_data, uri) // Uriへデータの書き込み(※A) } _create.launch(FileCreateIntent(_filename)) // Clientアプリの起動
fun Context.writeToUri_Resolver(data: ByteArray, uri: Uri) { try { contentResolver.openOutputStream(uri, "w")?.use { outputStream -> outputStream.write(data) outputStream.flush() } } catch (e: Exception) { Log.i(TAG, "[writeToUri] ${e}") } }
サンプルはアクセス方法を大まかに表現したものです。
※詳細は以下を参照
「SAFを使用してファイルを開く」
アクセス先の分類
アクセス方法をアクセス先毎に分類しました。
アクセス先により、利用できないアクセス方法があります。また、最適なアクセス方法が存在するので、使い分けが必要です。
上段と下段は次の意味を持ちます。
- 上段:「アプリ自身が作成したファイル(自)」へアクセスする場合
- 下段:「他のアプリが作成したファイル(他)」へアクセスする場合
内部ストレージ
利用可能なアクセス方法は「Java(Kotlin)/ Android API」のみです。
内部ストレージ /data/data/ユーザーID | Java / Android API | Media Store API | SAF | |
---|---|---|---|---|
アプリ固有 (パッケージ名/files) | 他:× | |||
※自:自アプリのファイル 他:他アプリのファイル ◎:アクセスできる(最適) ○:アクセスできる △:アクセスできる(不適または制限有) ×:アクセスできない 空:アクセスできない(サポート外) w:書き込みできる r:読み出しできる p:パーミッションが必要 |
※内部ストレージの詳細は「ストレージの用途別記憶領域とボリューム」を参照
※アクセス方法の詳細は以下を参照
「内部ストレージにJava/Android APIでアクセス」
外部ストレージ_プライマリ
「メディアデータ」のアクセスは「Media Store」が最適です。他の方法は、データベースの更新が行われません。
「ドキュメント・他のファイル」のアクセスは「SAF(Storage Access Framework)」が最適です。SAFは、ピッカー(GUI)を使いユーザの意思で保存先(ディレクトリ)とファイル名が決められます。保存先を新たに作ることも可能です。
アクセスするパーミッションと権限の範囲が、「対象範囲別ストレージ(API≧29)」と「きめ細かいメディア権限(API≧33)」で大きく変更されている点に注意して下さい。
外部ストレージ プライマリ /storage/emulated/ユーザーID | Java / Android API | Media Store API | SAF | |
---|---|---|---|---|
メディアデータ | Pictures | 他:△wrp | 他:◎wrp | 他:△wr |
DCIM | ||||
Movies | ||||
Music | ||||
Alarms | ||||
Notifications | ||||
Podcasts | ||||
Ringtones | ||||
Audiobooks(API≧30) | ||||
Recordings(API≧31) | ||||
ドキュメント 他のファイル | Downloads | 他:○wrp | 他:◎wrp | 他:◎wr |
Documants | ||||
Android (Android/dataを除く) | ||||
ユーザーフォルダ | ||||
ユーザーファイル | ||||
アプリ別 Android/data/パッケージ名/files | 他:△wrp | 他:○wr |
||
※自:自アプリのファイル 他:他アプリのファイル ◎:アクセスできる(最適) ○:アクセスできる △:アクセスできる(不適または制限有) ×:アクセスできない 空:アクセスできない(サポート外) w:書き込みできる r:読み出しできる p:パーミッションが必要 |
外部ストレージ プライマリ /storage/emulated/ユーザーID | Java / Android API | Media Store API | SAF | |
---|---|---|---|---|
メディアデータ | Pictures | 他:× | 他:◎ rp | 他:△wr |
DCIM | ||||
Movies | ||||
Music | ||||
Alarms | ||||
Notifications | ||||
Podcasts | ||||
Ringtones | ||||
Audiobooks(API≧30) | ||||
Recordings(API≧31) | ||||
ドキュメント 他のファイル | Downloads | 他:× | 他:× | 他:◎wr |
Documants | ||||
Android (Android/dataを除く) | ||||
ユーザーフォルダ | ||||
ユーザーファイル | ||||
アプリ別 Android/data/パッケージ名/files | 他:× | 他:○wr |
||
※自:自アプリのファイル 他:他アプリのファイル ◎:アクセスできる(最適) ○:アクセスできる △:アクセスできる(不適または制限有) ×:アクセスできない 空:アクセスできない(サポート外) w:書き込みできる r:読み出しできる p:パーミッションが必要 |
外部ストレージ プライマリ /storage/emulated/ユーザーID | Java / Android API | Media Store API | SAF | |
---|---|---|---|---|
メディアデータ | Pictures | 他:× | 他:◎ rp ※1 | 他:△wr |
DCIM | ||||
Movies | ||||
Music | ||||
Alarms | ||||
Notifications | ||||
Podcasts | ||||
Ringtones | ||||
Audiobooks(API≧30) | ||||
Recordings(API≧31) | ||||
ドキュメント 他のファイル | Downloads | 他:× | 他:× | 他:◎wr |
Documants | ||||
Android (Android/dataを除く) | 他:× | |||
ユーザーフォルダ | ||||
ユーザーファイル | ||||
アプリ別 Android/data/パッケージ名/files | 他:× | 他:× |
||
※自:自アプリのファイル 他:他アプリのファイル ◎:アクセスできる(最適) ○:アクセスできる △:アクセスできる(不適または制限有) ×:アクセスできない 空:アクセスできない(サポート外) w:書き込みできる r:読み出しできる p:パーミッションが必要 ※1:書き込みはファイル毎に権限の取得が必要、通常のパーミッションとは別 |
外部ストレージ プライマリ /storage/emulated/ユーザーID | Java / Android API | Media Store API | SAF | |
---|---|---|---|---|
メディアデータ | Pictures | 他:× | 他:◎ rp ※1 | 他:△wr |
DCIM | ||||
Movies | ||||
Music | ||||
Alarms | ||||
Notifications | ||||
Podcasts | ||||
Ringtones | ||||
Audiobooks(API≧30) | ||||
Recordings(API≧31) | ||||
ドキュメント 他のファイル | Downloads | 他:× | 他:× | 他:◎wr |
Documants | ||||
Android (Android/dataを除く) | 他:× | |||
ユーザーフォルダ | ||||
ユーザーファイル | ||||
アプリ別 Android/data/パッケージ名/files | 他:× | 他:× |
||
※自:自アプリのファイル 他:他アプリのファイル ◎:アクセスできる(最適) ○:アクセスできる △:アクセスできる(不適または制限有) ×:アクセスできない 空:アクセスできない(サポート外) w:書き込みできる r:読み出しできる p:パーミッションが必要(コレクション毎) ※1:書き込みはファイル毎に権限の取得が必要、通常のパーミッションとは別 |
※外部ストレージ_プライマリの詳細は「ストレージの用途別記憶領域とボリューム」を参照
※アクセス方法の詳細は以下を参照
「外部ストレージ_プライマリにJava/Android APIでアクセス」
外部ストレージ_セカンダリ
「ドキュメント・他のファイル」のアクセスは「SAF(Storage Access Framework)」が最適です。SAFは、ピッカー(GUI)を使いユーザの意思で保存先(ディレクトリ)とファイル名が決められます。保存先を新たに作ることも可能です。
主に他のデバイス(他の携帯端末やパソコンなど)と共有するデータを保存する領域なので、ユーザの意思(公開してもよいか?!)を重視したアクセス方法にします。
外部ストレージ セカンダリ /storage/NNN-NNN/ | Java / Android API | Media Store API | SAF | |
---|---|---|---|---|
ドキュメント 他のファイル | Downloads | 他:× | 他:◎wr |
|
Documents | ||||
Android (Android/dataを除く) |
||||
ユーザーフォルダ | ||||
ユーザーファイル | ||||
アプリ別 (Android/data/パッケージ名/files) | 他:△ rp | 他:○wr |
||
※自:自アプリのファイル 他:他アプリのファイル ◎:アクセスできる(最適) ○:アクセスできる △:アクセスできる(不適または制限有) ×:アクセスできない 空:アクセスできない(サポート外) w:書き込みできる r:読み出しできる p:パーミッションが必要 |
外部ストレージ セカンダリ /storage/NNN-NNN/ | Java / Android API | Media Store API | SAF | |
---|---|---|---|---|
ドキュメント 他のファイル | Downloads | 他:× | 他:◎wr |
|
Documents | ||||
Android (Android/dataを除く) |
||||
ユーザーフォルダ | ||||
ユーザーファイル | ||||
アプリ別 (Android/data/パッケージ名/files) | 他:× | 他:○wr |
||
※自:自アプリのファイル 他:他アプリのファイル ◎:アクセスできる(最適) ○:アクセスできる △:アクセスできる(不適または制限有) ×:アクセスできない 空:アクセスできない(サポート外) w:書き込みできる r:読み出しできる p:パーミッションが必要 |
外部ストレージ セカンダリ /storage/NNN-NNN/ | Java / Android API | Media Store API | SAF | |
---|---|---|---|---|
ドキュメント 他のファイル | Downloads | 他:× | 他:◎wr |
|
Documents | ||||
Android (Android/dataを除く) | 他:× |
|||
ユーザーフォルダ | ||||
ユーザーファイル | ||||
アプリ別 (Android/data/パッケージ名/files) | 他:× | 他:× |
||
※自:自アプリのファイル 他:他アプリのファイル ◎:アクセスできる(最適) ○:アクセスできる △:アクセスできる(不適または制限有) ×:アクセスできない 空:アクセスできない(サポート外) w:書き込みできる r:読み出しできる p:パーミッションが必要 |
※外部ストレージ_セカンダリの詳細は「ストレージの用途別記憶領域とボリューム」を参照
※アクセス方法の詳細は以下を参照
「外部ストレージ_セカンダリにJava/Android APIでアクセス」
Appendix:Googleのドキュメント
StorageのドキュメントがGoogleから提供されています。詳細は以下のリンクを参照してください。
Storageについて、ほぼ網羅されたドキュメントだと思われます。しかし、非常に説明が難解です。
関連記事:
