「外部ストレージ_プライマリ」にアクセスする方法について、まとめます。
「外部ストレージ_プライマリ」は、アプリ間で共有するデータを保存するストレージです。
主にカメラ、音楽プレーヤー、動画プレーヤーで扱うデータを保存します。
「外部ストレージ_プライマリ」に保存したデータは、他のアプリに公開することになるので、秘匿性の高いデータの保存に適しません。
※環境:Android Studio Narwhal | 2025.1.1 Patch 1
目次
外部ストレージ_プライマリ
「外部ストレージ_プライマリ」はアプリ間で共有するデータを保存するストレージです。
保存されるデータは、「メディアデータ」「ドキュメント・他のファイル」「アプリ別」に分類されます。
# pwd /storage/emulated # ls -ld 0/* 0/Android/data/com.example.myapp_a/* ↓UserID drwxrwx--x 2 root sdcard_rw 4096 2025-07-31 02:26 0/Alarms drwxrwx--x 3 root sdcard_rw 4096 2025-07-31 02:26 0/Android drwxrwx--x 2 u0_a85 sdcard_rw 4096 2025-07-31 02:30 0/Android/data/com.example.myapp_a/files drwxrwx--x 2 root sdcard_rw 4096 2025-07-31 02:26 0/DCIM drwxrwx--x 2 root sdcard_rw 4096 2025-07-31 02:26 0/Download drwxrwx--x 2 root sdcard_rw 4096 2025-07-31 02:26 0/Movies drwxrwx--x 2 root sdcard_rw 4096 2025-07-31 02:26 0/Music drwxrwx--x 2 root sdcard_rw 4096 2025-07-31 02:26 0/Notifications drwxrwx--x 2 root sdcard_rw 4096 2025-07-31 02:26 0/Pictures drwxrwx--x 2 root sdcard_rw 4096 2025-07-31 02:26 0/Podcasts drwxrwx--x 2 root sdcard_rw 4096 2025-07-31 02:26 0/Ringtones ※エミュレータ(API28)で確認
# pwd /storage/emulated # ls -ld 0/* 0/Android/data/com.example.myapp_a/* ↓UserID drwxrwx--x 2 root sdcard_rw 4096 2025-08-01 13:17 0/Alarms drwxrwx--x 4 root sdcard_rw 4096 2025-08-01 13:17 0/Android drwxrwx--x 2 u0_a146 sdcard_rw 4096 2025-08-01 13:18 0/Android/data/com.example.myapp_a/files drwxrwx--x 2 root sdcard_rw 4096 2025-08-01 13:17 0/DCIM drwxrwx--x 2 root sdcard_rw 4096 2025-08-01 13:17 0/Download drwxrwx--x 2 root sdcard_rw 4096 2025-08-01 13:17 0/Movies drwxrwx--x 2 root sdcard_rw 4096 2025-08-01 13:17 0/Music drwxrwx--x 2 root sdcard_rw 4096 2025-08-01 13:17 0/Notifications drwxrwx--x 2 root sdcard_rw 4096 2025-08-01 13:17 0/Pictures drwxrwx--x 2 root sdcard_rw 4096 2025-08-01 13:17 0/Podcasts drwxrwx--x 2 root sdcard_rw 4096 2025-08-01 13:17 0/Ringtones ※エミュレータ(API29)で確認
# pwd /storage/emulated # ls -ld 0/* 0/Android/data/com.example.myapp_a/* ↓UserID drwx------ 2 u0_a163 u0_a163 4096 2025-08-01 13:21 0/Alarms drwxrws--x 5 media_rw media_rw 4096 2025-08-01 13:21 0/Android drwxrws--- 2 u0_a167 ext_data_rw 4096 2025-08-01 13:21 0/Android/data/com.example.myapp_a/files drwx------ 2 u0_a163 u0_a163 4096 2025-08-01 13:21 0/Audiobooks drwx------ 2 u0_a163 u0_a163 4096 2025-08-01 13:21 0/DCIM drwx------ 2 u0_a163 u0_a163 4096 2025-08-01 13:21 0/Documents drwx------ 2 u0_a163 u0_a163 4096 2025-08-01 13:21 0/Download drwx------ 3 u0_a163 u0_a163 4096 2025-08-01 13:21 0/Movies drwx------ 3 u0_a163 u0_a163 4096 2025-08-01 13:21 0/Music drwx------ 2 u0_a163 u0_a163 4096 2025-08-01 13:21 0/Notifications drwx------ 3 u0_a163 u0_a163 4096 2025-08-01 13:21 0/Pictures drwx------ 2 u0_a163 u0_a163 4096 2025-08-01 13:21 0/Podcasts drwx------ 2 u0_a163 u0_a163 4096 2025-08-01 13:21 0/Ringtones ※エミュレータ(API30)で確認
# pwd /storage/emulated # ls -ld 0/* 0/Android/data/com.example.myapp_a/* ↓UserID drwxrws--- 2 u0_a163 media_rw 4096 2025-08-01 13:23 0/Alarms drwxrws--x 5 media_rw media_rw 4096 2025-08-01 13:23 0/Android drwxrws--- 2 u0_a174 ext_data_rw 4096 2025-08-01 13:23 0/Android/data/com.example.myapp_a/files drwxrws--- 2 u0_a163 media_rw 4096 2025-08-01 13:23 0/Audiobooks drwxrws--- 2 u0_a163 media_rw 4096 2025-08-01 13:23 0/DCIM drwxrws--- 2 u0_a163 media_rw 4096 2025-08-01 13:23 0/Documents drwxrws--- 2 u0_a163 media_rw 4096 2025-08-01 13:23 0/Download drwxrws--- 3 u0_a163 media_rw 4096 2025-08-01 13:23 0/Movies drwxrws--- 3 u0_a163 media_rw 4096 2025-08-01 13:23 0/Music drwxrws--- 2 u0_a163 media_rw 4096 2025-08-01 13:23 0/Notifications drwxrws--- 3 u0_a163 media_rw 4096 2025-08-01 13:23 0/Pictures drwxrws--- 2 u0_a163 media_rw 4096 2025-08-01 13:23 0/Podcasts drwxrws--- 2 u0_a163 media_rw 4096 2025-08-01 13:23 0/Recordings drwxrws--- 2 u0_a163 media_rw 4096 2025-08-01 13:23 0/Ringtones ※エミュレータ(API33)で確認
データを「他のアプリと共有する」は「他のアプリに公開する」と同意です。悪意のあるアプリがインストールされた場合に、このアプリを経由してデータ(個人情報)が漏洩します。
ですので、秘匿性の高いデータの保存に適しません。
アクセスの方法
「Java/Android API」によるアクセスが可能です。
ただし、メディアデータを書き込んでも、Media Storeが管理するコレクション(データベース、images/video/musicの3つ)へ登録されません(△)。注意して下さい。
メディアデータのアクセスについては「Media Store API」の利用が最適です(◎)。
外部ストレージ プライマリ /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」によるアクセスは「間接的なアクセス」で行います。間接的なアクセスとは、以下の通りです。
Fileによる間接的なアクセスFileオブジェクトへ前もって保存場所を指定しておきます。Fileオブジェクトが示す場所(パス)にアクセスする方法です。
パーミッションの取得
一部のアクセス(表で「p」の付くもの)で、パミッションの取得が必要です。
※詳細は「外部ストレージへアクセスするパーミッションと権限の範囲」を参照
メディアデータ
間接的なアクセスでデータを外部ストレージへ書き込みます。
パス(保存先)の取得
getExternalStoragePublicDirectoryを使うと、Android APIに定義されているパスが取得できます。
val _bucket = Environment.DIRECTORY_PICTURES // val _bucket = Environment.DIRECTORY_DCIM // val _bucket = Environment.DIRECTORY_MOVIES // val _bucket = Environment.DIRECTORY_MUSIC // val _bucket = Environment.DIRECTORY_ALARMS // val _bucket = Environment.DIRECTORY_NOTIFICATIONS // val _bucket = Environment.DIRECTORY_PODCASTS // val _bucket = Environment.DIRECTORY_RINGTONES // val _bucket = Environment.DIRECTORY_DOCUMENTS // val _bucket = Environment.DIRECTORY_DOWNLOADS val _envExtDir: File = Environment.getExternalStoragePublicDirectory(_bucket)
Environment.DIRECTORY_PICTURES ⇒ /storage/emulated/0/Pictures Environment.DIRECTORY_DCIM ⇒ /storage/emulated/0/DCIM Environment.DIRECTORY_MOVIES ⇒ /storage/emulated/0/Movies Environment.DIRECTORY_MUSIC ⇒ /storage/emulated/0/Music Environment.DIRECTORY_ALARMS ⇒ /storage/emulated/0/Alarms Environment.DIRECTORY_NOTIFICATIONS ⇒ /storage/emulated/0/Notifications Environment.DIRECTORY_PODCASTS ⇒ /storage/emulated/0/Podcasts Environment.DIRECTORY_RINGTONES ⇒ /storage/emulated/0/Ringtones Environment.DIRECTORY_DOCUMENTS ⇒ /storage/emulated/0/Documents Environment.DIRECTORY_DOWNLOADS ⇒ /storage/emulated/0/Downloads
バスの示すディレクトリ(Picture,DCIM,…)が、実際のストレージ上に準備されている(存在する)かどうかは、端末メーカーによるAndroidの実装次第です。準備されている場合が多いと思います。
書き込み
File#outputStreamを用いると、Fileに指定した保存先へ書き込まれます。
fun writeFile_Basic(data: ByteArray, file: File) { try { file.outputStream().use { stream -> stream.write(data) } } catch (e: Exception) { Log.i(TAG, "[write] ${e}") } }
バスの示すディレクトリ(Picture,DCIM,…)が準備されていない場合もあります。パスの存在を確認し、無い場合はディレクトリを作成するようにします。
val _path = Environment.getExternalStoragePublicDirectory(bucket) if(! _path.exists() and ! _path.mkdir()) throw FileNotFoundException() val _file = File(_path, _filename) writeFile_Basic(_data, _file)
# pwd /storage/emulated/0 # ls -ld * */* drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 Alarms drwxrwx--x 3 root sdcard_rw 4096 2025-07-16 01:56 Android drwxrwx--x 8 root sdcard_rw 4096 2025-07-16 02:01 Android/data drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 DCIM drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 Download drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 Movies drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 Music drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 Notifications drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 12:40 Pictures -rw-rw---- 1 root sdcard_rw 47891 2025-07-16 12:40 Pictures/1752669649349.jpg drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 Podcasts drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 Ringtones ※エミュレータ(API28)で実行 ※「bucket = Environment.DIRECTORY_PICTURES」の時
書き込み以外の操作
その他の操作(読み出し、ファイル削除、ディレクトリ作成/削除、ファイル一覧)は、内部ストレージにアクセスする場合と同じです。
※詳細は「内部ストレージにJava/Android APIでアクセス」を参照
ドキュメント・その他ファイル
間接的なアクセスでデータを外部ストレージへ書き込みます。
パス(保存先)の取得
getExternalStoragePublicDirectoryを使うと、Android APIに定義されているパスが取得できます。ユーザ定義のディレクトリ(”UserDir”など)も可能です。
val _bucket = Environment.DIRECTORY_DOWNLOADS // val _bucket = Environment.DIRECTORY_DOCUMENTS // val _bucket = "UserDir" val _envExtDir: File = Environment.getExternalStoragePublicDirectory(_bucket)
Environment.DIRECTORY_DOWNLOADS ⇒ /storage/emulated/0/Downloads Environment.DIRECTORY_DOCUMENTS ⇒ /storage/emulated/0/Documents "UserDir" ⇒ /storage/emulated/0/UserDir
getExternalStorageDirectoryを使うと、Android APIに定義されているトップパスが取得できます。
val _envExtDir: File = Environment.getExternalStorageDirectory()
⇒ /storage/emulated/0
バスの示すディレクトリ(Documents,…)が、実際のストレージ上に準備されている(存在する)かどうかは、端末メーカーによるAndroidの実装次第です。
書き込み
メディアデータの場合と同じです。
# pwd /storage/emulated/0 # ls -ld * */* drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 Alarms drwxrwx--x 3 root sdcard_rw 4096 2025-07-16 01:56 Android drwxrwx--x 8 root sdcard_rw 4096 2025-07-16 02:01 Android/data drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 DCIM drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 Download drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 Movies drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 Music drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 Notifications drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 12:45 Pictures drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 Podcasts drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 01:57 Ringtones drwxrwx--x 2 root sdcard_rw 4096 2025-07-16 12:45 UserDir -rw-rw---- 1 root sdcard_rw 47891 2025-07-16 12:45 UserDir/1752669941180.jpg ※エミュレータ(API28)で実行 ※「bucket = "UserDir"」の時
書き込み以外の操作
その他の操作(読み出し、ファイル削除、ディレクトリ作成/削除、ファイル一覧)は、内部ストレージにアクセスする場合と同じです。
※詳細は「内部ストレージにJava/Android APIでアクセス」を参照
アプリ別
間接的なアクセスでデータを外部ストレージへ書き込みます。
パス(保存先)の取得
getExternalFilesDirを使うと、Android APIに定義されているパスが取得できます。
val _bucket = Environment.DIRECTORY_PICTURES // val _bucket = Environment.DIRECTORY_DCIM // val _bucket = Environment.DIRECTORY_MOVIES // val _bucket = Environment.DIRECTORY_MUSIC // val _bucket = Environment.DIRECTORY_ALARMS // val _bucket = Environment.DIRECTORY_NOTIFICATIONS // val _bucket = Environment.DIRECTORY_PODCASTS // val _bucket = Environment.DIRECTORY_RINGTONES // val _bucket = Environment.DIRECTORY_DOCUMENTS // val _bucket = Environment.DIRECTORY_DOWNLOADS // val _bucket = Environment.DIRECTORY_DOWNLOADS // val _bucket = Environment.DIRECTORY_DOCUMENTS // val _bucket = "UserDir" val _ctxExtDir: File? = this@Activity.getExternalFilesDir(_bucket)
Environment.DIRECTORY_PICTURES ⇒ /storage/emulated/0/Android/data/パッケージ名/files/Pictures Environment.DIRECTORY_DCIM ⇒ /storage/emulated/0/Android/data/パッケージ名/files/DCIM Environment.DIRECTORY_MOVIES ⇒ /storage/emulated/0/Android/data/パッケージ名/files/Movies Environment.DIRECTORY_MUSIC ⇒ /storage/emulated/0/Android/data/パッケージ名/files/Music Environment.DIRECTORY_ALARMS ⇒ /storage/emulated/0/Android/data/パッケージ名/files/Alarms Environment.DIRECTORY_NOTIFICATIONS ⇒ /storage/emulated/0/Android/data/パッケージ名/files/Notifications Environment.DIRECTORY_PODCASTS ⇒ /storage/emulated/0/Android/data/パッケージ名/files/Podcasts Environment.DIRECTORY_RINGTONES ⇒ /storage/emulated/0/Android/data/パッケージ名/files/Ringtones Environment.DIRECTORY_DOCUMENTS ⇒ /storage/emulated/0/Android/data/パッケージ名/files/Documents Environment.DIRECTORY_DOWNLOADS ⇒ /storage/emulated/0/Android/data/パッケージ名/files/Downloads Environment.DIRECTORY_DOWNLOADS ⇒ /storage/emulated/0/Android/data/パッケージ名/files/Downloads Environment.DIRECTORY_DOCUMENTS ⇒ /storage/emulated/0/Android/data/パッケージ名/files/Documents "UserDir" ⇒ /storage/emulated/0/Android/data/パッケージ名/files/UserDir
getExternalFilesDirを「引数=null」で使うと、Android APIに定義されているトップパスが取得できます。
val _ctxExtDir: File? = this@Activity.getExternalFilesDir(null)
⇒ /storage/emulated/0/Android/data/パッケージ名/files
パスを取得すると同時に、パスの示すディレクトリツリー全体(Android以下)が、実際のストレージ上に自動作成されます。
また、ストレージが利用できない場合はnullになることがあります。
書き込み
File#outputStreamを用いると、Fileに指定した保存先へ書き込まれます。
fun writeFile_Basic(data: ByteArray, file: File) { try { file.outputStream().use { stream -> stream.write(data) } } catch (e: Exception) { Log.i(TAG, "[write] ${e}") } }
getExternalFilesDirは「null」を返すことがあります。回避するためにパスのnull判定を行い、nullでない場合のみ書き込みを行うようにします。
val _path = this@Activity.getExternalFilesDir(bucket) // 末端までのディレクトリを自動作成 _path?.let { val _file = File(_path, filename) writeFile_Basic(_data, _file) }
# pwd /storage/emulated/0/Android/data/パッケージ名/files # ls -ld * */* drwxrwx--x 2 u0_a85 sdcard_rw 4096 2025-07-16 13:20 Movies -rw-rw---- 1 u0_a85 sdcard_rw 47891 2025-07-16 13:20 Movies/1752672058499.jpg ※エミュレータ(API28)で実行 ※「bucket = Environment.DIRECTORY_MOVIES」の時
書き込み以外の操作
その他の操作(読み出し、ファイル削除、ディレクトリ作成/削除、ファイル一覧)は、内部ストレージにアクセスする場合と同じです。
※詳細は「内部ストレージにJava/Android APIでアクセス」を参照
関連記事: