メディアデータはMedia Storeを使ったアクセスが最適です。
その理由は、メディア特有の付加情報を使って、データを管理できるからです。
管理されたデータはブログラムから扱い易いです。また、ユーザの使い勝手(エクスペリエンス)も向上します。
バケットはメディアデータを管理する付加情報の一つです。
無くてもアクセスは可能ですが、積極的に取り入れた方が良いと思います。
今回は「ファイル名とバケットを指定したアクセス」について、まとめます。
「API≦28」と「API≧29」で動作が異なります。注意して下さい。
※環境:Android Studio Narwhal Feature Drop | 2025.1.2
目次
バケットとは
メディアデータはメディアタイプ(images/video/audio)で分類されます。
更に、各データはカテゴリー(Pictures/Movies/Musicなど)で分類されます。
このカテゴリーをMedia Storeでは「バケット(Bucket)」と呼んでいます。

各バケットはストレージ上にディレクトリを持ちます。そして、メディアファイルは属するバケットのディレクトリへ格納するようにします。
# pwd /storage/emulated/0 # ls -ld * drwxrws--- 2 u0_a144 media_rw 4096 2025-08-17 01:24 Alarms drwxrws--x 5 media_rw media_rw 4096 2025-08-17 01:24 Android drwxrws--- 2 u0_a144 media_rw 4096 2025-08-17 01:24 Audiobooks drwxrws--- 2 u0_a144 media_rw 4096 2025-08-17 01:24 DCIM drwxrws--- 2 u0_a144 media_rw 4096 2025-08-17 01:24 Documents drwxrws--- 2 u0_a144 media_rw 4096 2025-08-17 01:24 Download drwxrws--- 3 u0_a144 media_rw 4096 2025-08-17 01:24 Movies drwxrws--- 3 u0_a144 media_rw 4096 2025-08-17 01:24 Music drwxrws--- 2 u0_a144 media_rw 4096 2025-08-17 01:24 Notifications drwxrws--- 3 u0_a144 media_rw 4096 2025-08-17 01:24 Pictures drwxrws--- 2 u0_a144 media_rw 4096 2025-08-17 01:24 Podcasts drwxrws--- 2 u0_a144 media_rw 4096 2025-08-17 01:24 Recordings drwxrws--- 2 u0_a144 media_rw 4096 2025-08-17 01:24 Ringtones ※エミュレータ―(API 31)で確認
このように、メディアファイルをバケット(ディレクトリ)で管理する仕組みが、Media Storeに備わっています。
ファイル名とバケットを指定したアクセス
Media Storeを使った「アクセスの基本」と、動作の有様は同じです。
※アクセスの基本の詳細は「ImagesデータへMedia Storeでアクセス(API≧29)」を参照
ただ、relative_pathと_display_namesを指定された値に置き換えるだけです。
メディア情報の追加
ファイル名とバケットを指定したアクセスにおいて、データベースのテーブルへメディア情報を追加する方法は、次の通りです。
_dataは「relative_pathと_display_nameから自動生成」されます。ですので、relative_pathと_display_nameを指定された値で登録するように、ContentValuesを作ります。
例えば、バケットを「DCIM」、ファイル名を「photo.png」にしたければ、メディア情報の_dataフィールドは「/…/DCIM/photo.png」になります。
fun Context.insertImage(
data: ByteArray,
bucket: String,
filename: String
): Uri? {
val _contentValues = ContentValues().apply {
put(DisplayNameKey, filename)
put(RelativePathKey, bucket)
}
val _mediaUri = contentResolver.insert(ContentUri, _contentValues)
_mediaUri?.let { writeToUri_Resolver(data, _mediaUri) }
System.out.println("Test !!")
return _mediaUri
}
insertが実行されると、表のようなメディア情報が作成されて、そのレコードがデータベースへ登録されます。
| カラム | 意味 | フィールド値 |
|---|---|---|
| _id | プライマリキー | ユニークな連番 |
| _data | ファイルのパス | relative_pathと_display_nameから自動生成 (/storage/emulated/0/DCIM/photo.png) |
| _display_name | 表示名 | 指定した値 (photo.png) |
| mime_type | マイムタイプ | _dataのファイル名の拡張子で決まる (image/png) |
| bucket_display_name | バケット名 | _dataの格納フォルダ名 (DCIM) |
| bucket_id | バケットID | _dataの格納フォルダのパスのハッシュ値 (※) |
| relative_path | 格納フォルダ | 指定した値 (DCIM) |
| volume_name | 記録領域名 | external_primary |
| owner_package_name | 所有者 | アプリのパッケージ名 |
| title | タイトル | _dataの拡張子を除いたファイル名 (photo) |
| ※ハッシュ値の計算方法:「"/storage/emulated/0/DCIM".lowercase().hashCode()」 | ||
mime_type、bucket_display_name、bucket_id、titleのフィールド値は、_dataを元にして決まります。
# pwd /data/data/com.google.android.providers.media.module/databases # sqlite3 ./external.db sqlite> .headers on sqlite> .mode column sqlite> select _id,_data,_display_name,mime_type,bucket_display_name,bucket_id,title from images; _id _data _display_name mime_type bucket_display_name bucket_id title ---------- ---------------------------------- ------------- ---------- ------------------- ----------- ---------- 33 /storage/emulated/0/DCIM/photo.png photo.png image/png DCIM -2075821635 photo ※エミュレータ―(API 31)で確認
そして、メディア情報のURI(insertの戻り値)が確定します。
メディアファイルの書き込み
メディア情報のURIが確定していれば、書き込みはこのURIを使って行います。
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}") }
}
openOutputStreamが実行されると、URIが示すレコードがデータベースから読み出されます。そして、メディア情報の_dataフィールドが参照されて、指定されたファイルパスにデータを出力します。
val _uri = insertImage(_data, Environment.DIRECTORY_DCIM, "photo.png")
# pwd /storage/emulated/0 # ls -ld DCIM/* -rwxrwx--- 1 u0_a144 media_rw 47891 2025-08-17 01:39 DCIM/photo.png ※エミュレータ―(API 31)で確認
メディアファイルの読み出し
メディア情報のURIが確定していれば、読み出しはこのURIを使って行います。
fun Context.readFromUri_Resolver(uri: Uri): ByteArray {
val _os = ByteArrayOutputStream()
contentResolver.openInputStream(uri).use { stream ->
_os.use {
stream?.copyTo(_os)
}
}
return _os.toByteArray()
}
openInputStreamが実行されると、URIが示すレコードがデータベースから読み出されます。そして、メディア情報の_dataフィールドが参照されて、指定されているパスからデータを取得します。
val _data = _uri?.let { readFromUri_Resolver(it) }
Log.i(TAG, "Data = ${_data?.take(10)}")
Data = [71, 73, 70, 56, 55, 97, 24, 1, -46, 0]
注意:利用可能なバケット
メディアタイプ毎に利用可能なバケットの制限があります。
例えば、imagesデータ(media_type=1)はPictures/DCIMバケットのみに保存できます。
| バケット名 | パラメータ (Enviroment.****) | images (1) | video (3) | audio (2) | downloads (*) (API≧29) | files (*) |
|---|---|---|---|---|---|---|
| Pictures | DIRECTORY_PICTURES | ○ | ○ | ○ | ○ |
|
| DCIM | DIRECTORY_DCIM | ○ | ○ | ○ | ○ | |
| Movies | DIRECTORY_MOVIES | ○ | ○ | ○ | ○ | |
| Music | DIRECTORY_MUSIC | ○ | ○ | ○ | ○ | |
| Alarms | DIRECTORY_ALARMS | ○ | ○ | ○ | ○ | |
| Notifications | DIRECTORY_NOTIFICATIONS | ○ | ○ | ○ | ○ | |
| Podcasts | DIRECTORY_PODCASTS | ○ | ○ | ○ | ○ | |
| Ringtones | DIRECTORY_RINGTONES | ○ | ○ | ○ | ○ | |
| Audiobooks | DIRECTORY_AUDIOBOOKS (API≧29) | |||||
| Recordings | DIRECTORY_RECORDINGS (API≧31) | |||||
| Downloads | DIRECTORY_DOWNLOADS | ○ | ○ | ○ | ○ | |
| Documents | DIRECTORY_DOCUMENTS | ○ | ○ | ○ | ○ | |
| ※DIRECTORY_SCREENSHOTS(API≧29)はPictureまたはDCIMのサブ(下位)ディレクトリ ※DIRECTORY_AUDIOBOOKSは(API≧29)で存在するが、(API≧30)で利用可能になる ※タイトル欄の( )はmedia_type ・*はMIMEに従う、text/plainの場合は「media_type=0」 |
||||||
| バケット名 | パラメータ (Enviroment.****) | images (1) | video (3) | audio (2) | downloads (*) (API≧29) | files (*) |
|---|---|---|---|---|---|---|
| Pictures | DIRECTORY_PICTURES | ○ | ○ API≠29 | |||
| DCIM | DIRECTORY_DCIM | ○ | ○ | |||
| Movies | DIRECTORY_MOVIES | ○ | ||||
| Music | DIRECTORY_MUSIC | ○ | ||||
| Alarms | DIRECTORY_ALARMS | ○ | ||||
| Notifications | DIRECTORY_NOTIFICATIONS | ○ | ||||
| Podcasts | DIRECTORY_PODCASTS | ○ | ||||
| Ringtones | DIRECTORY_RINGTONES | ○ | ||||
| Audiobooks | DIRECTORY_AUDIOBOOKS (API≧29) | ○ API≧30 | ||||
| Recordings | DIRECTORY_RECORDINGS (API≧31) | ○ | ||||
| Downloads | DIRECTORY_DOWNLOADS | ○ | ○ | |||
| Documents | DIRECTORY_DOCUMENTS | ○ | ||||
| ※DIRECTORY_SCREENSHOTS(API≧29)はPictureまたはDCIMのサブ(下位)ディレクトリ ※DIRECTORY_AUDIOBOOKSは(API≧29)で存在するが、(API≧30)で利用可能になる ※タイトル欄の( )はmedia_type ・*はMIMEに従う、text/plainの場合は「media_type=0」 |
||||||
(参考)API≦28は、メディアタイプ毎に利用可能なバケットの制限はありません。。注意して下さい。
注意:バケットの識別方法
メディアファイルが所属するバケットは、表に示したカラムから識別できます。
- (a)バケット名を表すカラム(bucket_display_name,bucket_id,relative_path)
- (b)バケットを表すフラグ形式のカラム(is_music,is_alarm,など)
メディアデータのaudioは(a)(b)の両方を持ちます。
| メディアタイプ | バケット | 識別方法(カラム) | |
|---|---|---|---|
| Images(1) | Picture(Defailt) | bucket_id bucket_display_name | |
| DCIM | |||
| video(3) | Movie(Defailt) | ||
| Pictures | |||
| DCIM | |||
| audio(2) | Music(Defailt) | is_music | |
| Alarms | is_alarm | ||
| Notifications | is_notification | ||
| Podcasts | is_podcast | ||
| Ringtones | is_ringtone | ||
| ※DCIM:Digital Camera IMage ※メディアタイプの()はmedia_type値 |
|||
| メディアタイプ | バケット | 識別方法(カラム) | |
|---|---|---|---|
| Images(1) | Picture(Defailt) | bucket_id bucket_display_name relative_path | |
| DCIM | |||
| video(3) | Movie(Defailt) | ||
| Pictures | |||
| DCIM | |||
| audio(2) | Music(Defailt) | is_music | |
| Alarms | is_alarm | ||
| Notifications | is_notification | ||
| Podcasts | is_podcast | ||
| Ringtones | is_ringtone | ||
| Audiobooks(API≧29) | is_audiobook | ||
| Recordings(API≧31) | is_recording | ||
| ※DCIM:Digital Camera IMage ※メディアタイプの()はmedia_type値 |
|||
(参考)メディアデータのaudioは、API≦28の場合に(a)を持ちません。注意して下さい。
関連記事:
