Media Storeでファイル名とバケットを指定したアクセス(API≧29)

投稿日:  更新日:

メディアデータは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バケットのみに保存できます。

API≦28(参考)API≧29
バケット名パラメータ
(Enviroment.****)
images
(1)
 
video
(3)
 
audio
(2)
 
downloads
(*)
(API≧29)
files
(*)
 
PicturesDIRECTORY_PICTURES
 

 

 

 
DCIMDIRECTORY_DCIM
MoviesDIRECTORY_MOVIES
MusicDIRECTORY_MUSIC
AlarmsDIRECTORY_ALARMS
NotificationsDIRECTORY_NOTIFICATIONS
PodcastsDIRECTORY_PODCASTS
RingtonesDIRECTORY_RINGTONES
AudiobooksDIRECTORY_AUDIOBOOKS
(API≧29)
RecordingsDIRECTORY_RECORDINGS
(API≧31)
DownloadsDIRECTORY_DOWNLOADS
DocumentsDIRECTORY_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
(*)
 
PicturesDIRECTORY_PICTURES
 

API≠29
DCIMDIRECTORY_DCIM
MoviesDIRECTORY_MOVIES
MusicDIRECTORY_MUSIC
AlarmsDIRECTORY_ALARMS
NotificationsDIRECTORY_NOTIFICATIONS
PodcastsDIRECTORY_PODCASTS
RingtonesDIRECTORY_RINGTONES
AudiobooksDIRECTORY_AUDIOBOOKS
(API≧29)

API≧30
RecordingsDIRECTORY_RECORDINGS
(API≧31)
DownloadsDIRECTORY_DOWNLOADS
DocumentsDIRECTORY_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)の両方を持ちます。

API≦28(参考)API≧29
メディアタイプバケット識別方法(カラム)
Images(1)Picture(Defailt)bucket_id
bucket_display_name
DCIM
video(3)Movie(Defailt)
Pictures
DCIM
audio(2)Music(Defailt)is_music
Alarmsis_alarm
Notificationsis_notification
Podcastsis_podcast
Ringtonesis_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
Alarmsis_alarm
Notificationsis_notification
Podcastsis_podcast
Ringtonesis_ringtone
Audiobooks(API≧29)is_audiobook
Recordings(API≧31)is_recording
※DCIM:Digital Camera IMage
※メディアタイプの()はmedia_type値

(参考)メディアデータのaudioは、API≦28の場合に(a)を持ちません。注意して下さい。

スポンサーリンク

関連記事:

ストレージのリソースは、内部メモリー、外部メモリー、クラウドの3つがあります。 外部メモリーは、主にSDカードです。 このSDカードはAndroid端末の世代が進むにつれて、扱いを変えてきました。 リソースとSDカードを主眼に置いたストレージの変遷について、まとめます。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
Adoptable Storage(API≧23、Android 6.0)が導入されて、SDカードの扱い方をユーザ側で指定できるようになりました。 「Adoptable Storage」について、まとめます。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
ストレージはデータの用途別に記憶領域が分けられます。 保存先を守らないと、セキュリティリスクが発生したり、他のアプリと協調した動作が出来なくなったり、します。 ですので、適切な場所へデータを保存しましょう。 今回は「用途別記憶領域とボリューム」について、まとめます。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
ストレージへアクセスする方法は、「扱うデータの種類」「アクセス先」「セキュリティの確保」などの要件により、最適なアクセス方法が存在するので、使い分けが必要です。 今回は「アクセスする方法」について、まとめます。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
「内部ストレージ」にアクセスする方法について、まとめます。 「内部ストレージ」は、セキュリティが高いうえに、端末の内部メモリーに構築されるので、必ず存在します。 使いたい時に安心して使え、もっとも使い勝手のよいストレージと言えます。 アプリのデータを保存したいならば、保存先として真っ先に考えるストレージです。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
外部ストレージへアクセスするアプリは、パーミッション(許可)をユーザーから取得する必要があります。 パーミッションを得たアプリは、許可された権限の範囲内で、ストレージへアクセスが可能です。 これらは、ユーザーデータのプライバシー保護と密接に関係しています。 プライバシー保護をより強固にするために、パーミッションと権限の範囲の仕様は改変されてきました。 今回は、改変の歴史を辿りつつ、「パーミッションと権限の範囲」について、まとめます。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
「外部ストレージ_プライマリ」にアクセスする方法について、まとめます。 「外部ストレージ_プライマリ」は、アプリ間で共有するデータを保存するストレージです。 主にカメラ、音楽プレーヤー、動画プレーヤーで扱うデータを保存します。 「外部ストレージ_プライマリ」に保存したデータは、他のアプリに公開することになるので、秘匿性の高いデータの保存に適しません。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
「外部ストレージ_セカンダリ」にアクセスする方法について、まとめます。 「外部ストレージ_セカンダリ」は、デバイス間(または、アプリ間)で共有するデータを保存するストレージです。 デバイスとは、他の携帯端末やパソコンなどを指します。 ストレージがSDカードのような取り外し可能なリソース上に構築されているので、データの共有は取り外したストレージを他のデバイスへ取り付けて行います。 「外部ストレージ_セカンダリ」に保存したデータは、他のデバイスに公開することになるので、秘匿性の高いデータの保存に適しません。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
「外部ストレージ_プライマリ」に保存されるメディアデータは、Media Storeと呼ばれる特別な方法でアクセスします。 他の方法も可能ですが、Media Storeが最も適した方法です。 この「メディアデータへMedia Storeでアクセス」する方法を、まとめます。 この記事は、Imagesデータ編です。また、基本的なアクセス(読み書き)に的を絞って説明しています。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
メディアデータはデータベースによって管理されています。 Media Store APIを使ってメディアデータへアクセスしているのであれば、データベースの所在や構成などを意識する必要はありません。 ただ、「より複雑な制御をしたい場合」や「デバックを効率化したい場合」などに、データベースの知識が役立ちます。 今回は「メディアデータのデータベースによる管理」について、まとめます。 この記事は、Imagesデータ編です。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
「外部ストレージ_プライマリ」に保存されるメディアデータは、Media Storeと呼ばれる特別な方法でアクセスします。 他の方法も可能ですが、Media Storeが最も適した方法です。 この「メディアデータへMedia Storeでアクセス」する方法を、まとめます。 この記事は、Imagesデータ編です。また、基本的なアクセス(読み書き)に的を絞って説明しています。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
メディアデータはデータベースによって管理されています。 Media Store APIを使ってメディアデータへアクセスしているのであれば、データベースの所在や構成などを意識する必要はありません。 ただ、「より複雑な制御をしたい場合」や「デバックを効率化したい場合」などに、データベースの知識が役立ちます。 今回は「メディアデータのデータベースによる管理」について、まとめます。 この記事は、Imagesデータ編です。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
「外部ストレージ_プライマリ」に保存されるメディアデータは、Media Storeと呼ばれる特別な方法でアクセスします。 他の方法も可能ですが、Media Storeが最も適した方法です。 別の記事で「メディアデータへMedia Storeでアクセス」する方法を、まとめました。 その記事は、基本的なアクセスとして「追加(insert)&読み書き」のみを説明しています。 この記事は、上記に加えて「参照(query)・更新(update)・削除(delete)」を説明します。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
「外部ストレージ_プライマリ」に保存されるメディアデータは、データベースで管理されます。 Media Storeを使うと、このデータベースを通してメディアデータへアクセスできます。 データベース(SQLite)が持つ検索機能を使ってアクセス対象を絞り込めるので、とても便利です。 この記事は、「絞り込みアクセス」について、まとめます。 ※環境:Android Studio Narwhal | 2025.1.1 Patch 1 ...
メディアデータはMedia Storeを使ったアクセスが最適です。 その理由は、メディア特有の付加情報を使って、データを管理できるからです。 管理されたデータはブログラムから扱い易いです。また、ユーザの使い勝手(エクスペリエンス)も向上します。 バケットはメディアデータを管理する付加情報の一つです。 無くてもアクセスは可能ですが、積極的に取り入れた方が良いと思います。 今回は「ファイル名とバケットを指定したアクセス」について、まとめます。 「API≦28」と「API≧29」で動作が異なります。注意して下さい。 ※環境:Android Studio Narwhal Feature Drop | 2025.1.2 ...
スポンサーリンク