外部ストレージ_セカンダリにJava/Android APIでアクセス

投稿日:  更新日:

「外部ストレージ_セカンダリ」にアクセスする方法について、まとめます。

「外部ストレージ_セカンダリ」は、デバイス間(または、アプリ間)で共有するデータを保存するストレージです。

デバイスとは、他の携帯端末やパソコンなどを指します。

ストレージがSDカードのような取り外し可能なリソース上に構築されているので、データの共有は取り外したストレージを他のデバイスへ取り付けて行います。

「外部ストレージ_セカンダリ」に保存したデータは、他のデバイスに公開することになるので、秘匿性の高いデータの保存に適しません。

※環境:Android Studio Narwhal | 2025.1.1 Patch 1

スポンサーリンク

外部ストレージ_セカンダリ

「外部ストレージ_セカンダリ」はデバイス間(または、アプリ間)で共有するデータを保存するストレージです。

保存されるデータは、「ドキュメント・他のファイル」、「アプリ別」に分類されます。

外部ストレージのフォルダ

API≦28API=29API≧30
# pwd
/storage/0000-0000
# ls -ld * Android/data/com.example.myapp_a/*
drwxrwx--x 3 root   sdcard_rw 2048 2025-07-31 12:18 Android
drwxrwx--x 2 u0_a85 sdcard_rw 2048 2025-07-31 12:20 Android/data/com.example.myapp_a/files
drwxrwx--x 2 root   sdcard_rw 2048 2025-07-31 12:18 LOST.DIR

※エミュレータ(API28)で確認
# pwd
/storage/0E15-260A
# ls -ld * Android/data/com.example.myapp_a/*
drwxrwx--x 2 root    sdcard_rw 2048 2025-07-31 12:35 Alarms
drwxrwx--x 3 root    sdcard_rw 2048 2025-07-31 12:35 Android
drwxrwx--x 2 u0_a146 sdcard_rw 2048 2025-07-31 12:35 Android/data/com.example.myapp_a/files
drwxrwx--x 2 root    sdcard_rw 2048 2025-07-31 12:35 DCIM
drwxrwx--x 2 root    sdcard_rw 2048 2025-07-31 12:35 Download
drwxrwx--x 2 root    sdcard_rw 2048 2025-07-31 16:35 LOST.DIR
drwxrwx--x 2 root    sdcard_rw 2048 2025-07-31 12:35 Movies
drwxrwx--x 2 root    sdcard_rw 2048 2025-07-31 12:35 Music
drwxrwx--x 2 root    sdcard_rw 2048 2025-07-31 12:35 Notifications
drwxrwx--x 2 root    sdcard_rw 2048 2025-07-31 12:35 Pictures
drwxrwx--x 2 root    sdcard_rw 2048 2025-07-31 12:35 Podcasts
drwxrwx--x 2 root    sdcard_rw 2048 2025-07-31 12:35 Ringtones

※エミュレータ(API29)で確認
# pwd
/storage/12EB-0D1D
# ls -ld * Android/data/com.example.myapp_a/*
drwxrwx--- 2 root media_rw 2048 2025-07-31 12:41 Alarms
drwxrwx--- 3 root media_rw 2048 2025-07-31 12:41 Android
drwxrwx--- 2 root media_rw 2048 2025-07-31 12:41 Android/data/com.example.myapp_a/files
drwxrwx--- 2 root media_rw 2048 2025-07-31 12:41 Audiobooks
drwxrwx--- 2 root media_rw 2048 2025-07-31 12:41 DCIM
drwxrwx--- 2 root media_rw 2048 2025-07-31 12:41 Documents
drwxrwx--- 2 root media_rw 2048 2025-07-31 12:41 Download
drwxrwx--- 2 root media_rw 2048 2025-07-31 12:41 LOST.DIR
drwxrwx--- 3 root media_rw 2048 2025-07-31 12:41 Movies
drwxrwx--- 3 root media_rw 2048 2025-07-31 12:41 Music
drwxrwx--- 2 root media_rw 2048 2025-07-31 12:41 Notifications
drwxrwx--- 3 root media_rw 2048 2025-07-31 12:41 Pictures
drwxrwx--- 2 root media_rw 2048 2025-07-31 12:41 Podcasts
drwxrwx--- 2 root media_rw 2048 2025-07-31 12:41 Ringtones

※エミュレータ(API30)で確認

データを「他のデバイスと共有する」は「他のデバイスに公開する」と同意です。悪意のある人物がSDカードを手に入れた場合に、自分のパソコンを使って内容を盗み見ることが出来てしまします。

ですので、秘匿性の高いデータの保存に適しません。

スポンサーリンク

アクセスの方法

「Java/Android API」によるアクセスが可能です。

ただし、問題点が2つあります。それを理解した上で利用してください。

 問題点1 
アプリ別のパスはAndroid APIから取得出来ますが、ドキュメント・他のファイルのパスは取得できません。APIに取得する手段が用意されていないためです。

ですので、「アクセス可能な範囲はアプリ別の領域のみ」と考えるのが良さそうです。

無理にアクセスしたければ、ドキュメント・他のファイルのパスを、アプリ別の相対パスで作り出すしかありません(△)。

相対パスの例
val _base = this@Activity.getExternalSecondaryFilesDir(null)?.parentFile?.parentFile?.parentFile?.parentFile
// /storage/NNN-NNN/Android/data/パッケージ名/files ⇒ /storage/NNN-NNN
// ↑↑ アプリ別のパス                                   ↑↑ ドキュメント・他のファイルのパス
 問題点2 
作成したファイルは、他のデバイスからアクセスできません。

ですので、「デバイス間で(または、アプリ間)で共有するデータを保存する」という、外部ストレージ_セカンダリの本来の目的が達成できません。

外部ストレージ_セカンダリのアクセスについては「SAF」の利用が最適です(◎)。SAFであれば、共有データを作成できます。

AP≦28AP=29API≧30
外部ストレージ セカンダリ
/storage/NNN-NNN/
Java /
Android
API
Media Store
API
SAF
ドキュメント
他のファイル
Downloads
自:×   
他:×   
自:◎wr
他:◎wr
Documents
Android
(Android/dataを除く)
ユーザーフォルダ
ユーザーファイル
アプリ別
(Android/data/パッケージ名/files)
自:○wr 
他:△ rp
自:○wr
他:○wr
※自:自アプリのファイル
 他:他アプリのファイル
 ◎:アクセスできる(最適)
 ○:アクセスできる
 △:アクセスできる(不適または制限有)
 ×:アクセスできない
 空:アクセスできない(サポート外)
 w:書き込みできる
 r:読み出しできる
 p:パーミッションが必要
外部ストレージ セカンダリ
/storage/NNN-NNN/
Java /
Android
API
Media Store
API
SAF
ドキュメント
他のファイル
Downloads
自:×   
他:×   
自:◎wr
他:◎wr
Documents
Android
(Android/dataを除く)
ユーザーフォルダ
ユーザーファイル
アプリ別
(Android/data/パッケージ名/files)
自:○wr 
他:×   
自:○wr
他:○wr
※自:自アプリのファイル
 他:他アプリのファイル
 ◎:アクセスできる(最適)
 ○:アクセスできる
 △:アクセスできる(不適または制限有)
 ×:アクセスできない
 空:アクセスできない(サポート外)
 w:書き込みできる
 r:読み出しできる
 p:パーミッションが必要
外部ストレージ セカンダリ
/storage/NNN-NNN/
Java /
Android
API
Media Store
API
SAF
ドキュメント
他のファイル
Downloads
自:△wr 
他:×   
自:◎wr
他:◎wr
Documents
Android
(Android/dataを除く)
自:×   
他:×   
ユーザーフォルダ
ユーザーファイル
アプリ別
(Android/data/パッケージ名/files)
自:○wr 
他:×   
自:×  
他:×  
※自:自アプリのファイル
 他:他アプリのファイル
 ◎:アクセスできる(最適)
 ○:アクセスできる
 △:アクセスできる(不適または制限有)
 ×:アクセスできない
 空:アクセスできない(サポート外)
 w:書き込みできる
 r:読み出しできる
 p:パーミッションが必要

「Java/Android API」によるアクセスは「間接的なアクセス」で行います。間接的なアクセスとは、以下の通りです。

 Fileによる間接的なアクセス 

Fileオブジェクトへ前もって保存場所を指定しておきます。Fileオブジェクトが示す場所(パス)にアクセスする方法です。

スポンサーリンク

パーミッションの取得

一部のアクセス(表で「p」の付くもの)で、パミッションの取得が必要です。

※詳細は「外部ストレージへアクセスするパーミッションと権限の範囲」を参照

スポンサーリンク

アプリ別

間接的なアクセスでデータを外部ストレージへ書き込みます。

パス(保存先)の取得

getExternalFilesDirsを使うと、Android APIに定義されているボリューム毎のパスが、配列で取得できます。
※ボリュームについては「ストレージの用途別記憶領域とボリューム」を参照

val _bucket = Environment.DIRECTORY_PICTURES
//val _backet = null
 
val _ctxExtDirs: Array<File> = this@Activity.getExternalFilesDirs(_bucket)
Environment.DIRECTORY_PICTURES      ⇒ /storage/emulated/0/Android/data/パッケージ名/files/Pictures
                                       /storage/NNN-NNN/Android/data/パッケージ名/files/Pictures
null                                ⇒ /storage/emulated/0/Android/data/パッケージ名/files
                                       /storage/NNN-NNN/Android/data/パッケージ名/files

このパスの配列から、プログラムで外部ストレージ_セカンダリのパスを抽出します。

注意点は「ストレージのマウントを確認する」ことです。SDカードが取り外されている場合もあるからです。

fun Context.getExternalSecondaryFilesDir(
    type: String?,
    index: Int = 0
): File? {
    val _dirs = ArrayList<File>()
    val _manager = getSystemService(StorageManager::class.java)

    val _files = getExternalFilesDirs(type)
    _files.forEach {
        val _volume = _manager.getStorageVolume(it)
        val _isActive = _volume?.let {
            (! it.isPrimary) && (it.state == "mounted")
        }?:false
        if(_isActive) _dirs.add(it)
    }

    if(_dirs.size > index) return _dirs[index]
    else throw IOException("Directory not found !")
}
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.getExternalSecondaryFilesDir(_bucket)

パスを取得すると同時に、パスの示すディレクトリツリー全体(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}") }
}

getExternalSecondaryFilesDirは「null」を返すことがあります。回避するためにパスのnull判定を行い、nullでない場合のみ書き込みを行うようにします。

                val _path = this@Activity.getExternalSecondaryFilesDir(bucket) // 末端までのディレクトリを自動作成
				_path?.let {
                    val _file = File(it, filename)
                    writeFile_Basic(_data, _file)
                }
# pwd
/storage/0000-0000/Android/data/パッケージ名/files
# ls -ld Pictures Pictures/*
drwxrwx--x 2 u0_a85 sdcard_rw 2048 2025-08-01 01:08 Pictures
-rwxrwx--x 1 u0_a85 sdcard_rw   30 2025-08-01 01:08 Pictures/sample.txt

※エミュレータ(API28)で実行
※「bucket = Environment.DIRECTORY_PICTURES」の時

書き込み以外の操作

その他の操作(読み出し、ファイル削除、ディレクトリ作成/削除、ファイル一覧)は、内部ストレージにアクセスする場合と同じです。
※詳細は「内部ストレージにJava/Android APIでアクセス」を参照

スポンサーリンク

関連記事:

ストレージのリソースは、内部メモリー、外部メモリー、クラウドの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 ...
スポンサーリンク