内部ストレージにJava/Android APIでアクセス

投稿日:  更新日:

「内部ストレージ」にアクセスする方法について、まとめます。

「内部ストレージ」は、セキュリティが高いうえに、端末の内部メモリーに構築されるので、必ず存在します。

使いたい時に安心して使え、もっとも使い勝手のよいストレージと言えます。

アプリのデータを保存したいならば、保存先として真っ先に考えるストレージです。

※環境:Android Studio Narwhal | 2025.1.1 Patch 1

スポンサーリンク

内部ストレージ

「内部ストレージ」はアプリ固有のデータを保存する領域です。

アプリ間はパッケージ名(アプリ固有の文字列)のディレクトリで隔てられています。また、マルチユーザのユーザID毎に独立した領域になっています。
※マルチユーザー環境についていは「Android OSのマルチユーザー環境」を参照

内部ストレージのディレクトリ

# pwd
/data/user
# ls -ld 0/com.example.*/*                               ↓UserID
drwxrws--x 2 u0_a174 u0_a174_cache 4096 2025-04-19 02:42 0/com.example.myapp_a/cache
drwxrws--x 2 u0_a174 u0_a174_cache 4096 2025-04-19 02:42 0/com.example.myapp_a/code_cache
drwxrwx--x 2 u0_a174 u0_a174       4096 2025-04-19 02:42 0/com.example.myapp_a/files
drwxrws--x 2 u0_a175 u0_a175_cache 4096 2025-04-19 02:41 0/com.example.myapp_b/cache
drwxrws--x 2 u0_a175 u0_a175_cache 4096 2025-04-19 02:41 0/com.example.myapp_b/code_cache
drwxrwx--x 2 u0_a175 u0_a175       4096 2025-04-19 02:42 0/com.example.myapp_b/files
             ↑UID    ↑GID                                  ↑Package

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

アプリ固有のデータはサンドボックス内にあるので、他のアプリからアクセスは出来ません。厳重に守られます。

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

内部・外部ストレージ

スポンサーリンク

アクセスの方法

利用可能なアクセスの方法は「Java/Android API」のみです。

内部ストレージ
/data/data/ユーザーID
Java /
Android
API
Media Store
API
SAF
アプリ固有
(パッケージ名/files)
自:◎wr
他:×  
         
※自:自アプリのファイル
 他:他アプリのファイル
 ◎:アクセスできる(最適)
 ○:アクセスできる
 △:アクセスできる(不適または制限有)
 ×:アクセスできない
 空:アクセスできない(サポート外)
 w:書き込みできる
 r:読み出しできる
 p:パーミッションが必要

さらに、「Java/Android API」を使ってアクセスする方法は、2つに分けられます。

 Contextによる直接的なアクセス 

アプリ固有のデータの保存場所は決まっており、Contextに定義されています。Contextオブジェクトが示す既定の場所にアクセスする方法です。

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

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

スポンサーリンク

直接的なアクセス

既定の場所(/data/user/ユーザID/パッケージ名/files)へアクセスします。

書き込み

Context#openFileOutputを用いると、アプリ固有の保存先へ直に書き込まれます。

fun Context.writeFile_AppArea(
    data: ByteArray,
    filename: String
) {
    try {
        openFileOutput(filename, MODE_PRIVATE).use {
            it.write(data)
        }
    } catch (e: Exception) { Log.i(TAG, "[write] ${e}") }
}
                                writeFile_AppArea(_data, filename)
# pwd
/data/user/0/パッケージ名
# ls -ld */*
-rw-rw---- 1 u0_a174 u0_a174 47891 2025-07-12 12:42 files/1752324178427.jpg

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

読み出し

Context#openFileInputを用いると、アプリ固有の保存先から直に読み出されます。

fun Context.readFile_AppArea(filename: String): ByteArray {
    val _os = ByteArrayOutputStream()
    openFileInput(filename).use { stream ->
        _os.use {
            stream?.copyTo(_os)
        }
    }
    return _os.toByteArray()
}
                                val _data = readFile_AppArea("1752324178427.jpg")
                                Log.i(TAG, "Data = ${_data?.take(10)}")
Data = [71, 73, 70, 56, 55, 97, 24, 1, -46, 0]

ファイル削除

Context#deleteFileを用いると、アプリ固有の保存先からファイルを削除します。

# pwd
/data/user/0/パッケージ名
# ls -ld files/*
-rw-rw---- 1 u0_a174 u0_a174 47891 2025-07-14 06:15 files/1752473725549.jpg
-rw-rw---- 1 u0_a174 u0_a174 47891 2025-07-14 06:15 files/1752473726610.jpg
-rw-rw---- 1 u0_a174 u0_a174 47891 2025-07-14 06:15 files/1752473727634.jpg

※エミュレータ(API33)で確認
val _result = deleteFile("1752473727634.jpg")  // true:成功、false:失敗
# pwd
/data/user/0/パッケージ名
# ls -ld files/*
-rw-rw---- 1 u0_a174 u0_a174 47891 2025-07-14 06:15 files/1752473725549.jpg
-rw-rw---- 1 u0_a174 u0_a174 47891 2025-07-14 06:15 files/1752473726610.jpg

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

ディレクトリ作成・削除

Context#getDirを用いると、アプリ固有の保存先へディレクトリを作成します。

ただし、ディレクトリ名が「”app_”+指定した文字列」になります。また、filesと並んだ位置に作成されます。

                                val _file = getDir("temp", MODE_PRIVATE)
                                Log.i(TAG, "File = ${_file}")
File = /data/user/0/パッケージ名/app_temp
# pwd
/data/user/0/パッケージ名
# ls -ld *
drwxrwx--x 2 u0_a174 u0_a174       4096 2025-07-14 06:23 app_temp
drwxrws--x 2 u0_a174 u0_a174_cache 4096 2025-07-14 06:15 cache
drwxrws--x 2 u0_a174 u0_a174_cache 4096 2025-07-14 06:15 code_cache
drwxrwx--x 2 u0_a174 u0_a174       4096 2025-07-14 06:16 files

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

直接的なアクセスで行えるのは作成のみです。作成したディレクトリへのアクセスは、間接的なアクセス(後述)で行います。

例えば、ディレクトリ削除は以下のようになります。

val _result = File(dataDir, "app_temp").delete()  // true:成功、false:失敗
# pwd
/data/user/0/パッケージ名
# ls -ld *
drwxrws--x 2 u0_a174 u0_a174_cache 4096 2025-07-14 06:15 cache
drwxrws--x 2 u0_a174 u0_a174_cache 4096 2025-07-14 06:15 code_cache
drwxrwx--x 2 u0_a174 u0_a174       4096 2025-07-14 06:16 files

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

ファイル一覧

Context#fileListを用いると、アプリ固有の保存先のファイル一覧が得られます。

                            val _files = fileList()
                            _files.forEach { Log.i(TAG, "File = ${it}") }
# pwd
/data/user/0/パッケージ名
# ls -ld files/*
-rw-rw---- 1 u0_a174 u0_a174 47891 2025-07-14 13:19 files/1752499198910.jpg
-rw-rw---- 1 u0_a174 u0_a174 47891 2025-07-14 13:20 files/1752499200327.jpg
-rw-rw---- 1 u0_a174 u0_a174 47891 2025-07-14 13:20 files/1752499201082.jpg

※エミュレータ(API33)で確認
File = 1752499198910.jpg
File = 1752499200327.jpg
File = 1752499201082.jpg
スポンサーリンク

間接的なアクセス

Fileに指定した場所へアクセスします。

パス(保存場所)の取得

以下のように行うと、Android APIに定義されているパスが取得できます。

    val _dataDir: File = this@Activity.dataDir             // /data/user/0/パッケージ名
    val _filesDir: File = this@Activity.filesDir           // /data/user/0/パッケージ名/files
    val _cacheDir: File = this@Activity.cacheDir           // /data/user/0/パッケージ名/cache
    val _codeCacheDir: File = this@Activity.codeCacheDir   // /data/user/0/パッケージ名/code_cache
	

既定の場所は「files」ですが、「cache」「code_cache」と言ったディレクトリも利用可能です。

書き込み

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}") }
}
                                val _file = File(this@Activity.filesDir, filename)
                                writeFile_Basic(_data, _file)
# pwd
/data/user/0/パッケージ名
# ls -ld */*
-rw------- 1 u0_a174 u0_a174 47891 2025-07-13 01:24 files/1752369865239.jpg

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

読み出し

File#inputStreamを用いると、Fileに指定した保存先から読み出されます。

fun readFile_Basic(file: File): ByteArray {
    val _os = ByteArrayOutputStream()
    file.inputStream().use { stream ->
        _os.use {
            stream?.copyTo(_os)
        }
    }
    return _os.toByteArray()
}
                                val _file = File(this@Activity.filesDir, "1752369865239.jpg")
                                val _data = readFile_Basic(_file)
                                Log.i(TAG, "Data = ${_data?.take(10)}")
Data = [71, 73, 70, 56, 55, 97, 24, 1, -46, 0]

ファイル削除

File#deleteを用いると、Fileに指定したファイルを削除します。

# pwd
/data/user/0/パッケージ名
# ls -ld files/*
-rw------- 1 u0_a174 u0_a174 47891 2025-07-14 07:01 files/1752476467106.jpg
-rw------- 1 u0_a174 u0_a174 47891 2025-07-14 07:01 files/1752476468125.jpg
-rw------- 1 u0_a174 u0_a174 47891 2025-07-14 07:01 files/1752476469166.jpg

※エミュレータ(API33)で確認
                                val _file = File(this@Activity.filesDir, "1752476469166.jpg")
                                val _result = _file.delete()  // true:成功、false:失敗
# pwd
/data/user/0/パッケージ名
# ls -ld files/*
-rw------- 1 u0_a174 u0_a174 47891 2025-07-14 07:01 files/1752476467106.jpg
-rw------- 1 u0_a174 u0_a174 47891 2025-07-14 07:01 files/1752476468125.jpg

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

ディレクトリ作成・削除

File#mkdirを用いると、Fileに指定したディレクトリを作成します。

                                val _file = File(this@Activity.filesDir, "temp")
                                val _result = _file.mkdir()  // true:成功、false:失敗
# pwd
/data/user/0/パッケージ名
# ls -ld files/*
-rw------- 1 u0_a174 u0_a174 47891 2025-07-14 07:01 files/1752476467106.jpg
-rw------- 1 u0_a174 u0_a174 47891 2025-07-14 07:01 files/1752476468125.jpg
drwx------ 2 u0_a174 u0_a174  4096 2025-07-14 07:05 files/temp

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

File#deleteを用いると、Fileに指定したディレクトリを削除します。

                                val _file = File(this@Activity.filesDir, "temp")
                                val _result = _file.delete()  // true:成功、false:失敗
# pwd
/data/user/0/パッケージ名
# ls -ld files/*
-rw------- 1 u0_a174 u0_a174 47891 2025-07-14 07:01 files/1752476467106.jpg
-rw------- 1 u0_a174 u0_a174 47891 2025-07-14 07:01 files/1752476468125.jpg

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

ファイル一覧

File#listを用いると、Fileに指定したディレクトリのファイル一覧を得ます。

                                val _files = this@Activity.filesDir.list()
                                _files.forEach {
                                    Log.i(TAG, "File = ${it}")
                                }
# pwd
/data/user/0/パッケージ名
# ls -ld files/*
-rw------- 1 u0_a174 u0_a174 47891 2025-07-14 13:30 files/1752499851049.jpg
-rw------- 1 u0_a174 u0_a174 47891 2025-07-14 13:30 files/1752499851750.jpg
-rw------- 1 u0_a174 u0_a174 47891 2025-07-14 13:30 files/1752499853162.jpg

※エミュレータ(API33)で確認
File = 1752499851049.jpg
File = 1752499851750.jpg
File = 1752499853162.jpg
スポンサーリンク

File creation mode

直接的なアクセスにおいて、ファイルまたはディレクトリを作成する場合に「File creation mode」を指定します。

mode(Context.***)意味コメント
MODE_PRIVATEthe default mode, where the created file can only be accessed by the calling application (or all applications sharing the same user ID). ※ドキュメントより
-----
自アプリのみの読み書きが可能
デフォルト
MODE_APPENDfor use with openFileOutput(String, int), if the file already exists then write data to the end of the existing file instead of erasing it. ※ドキュメントより
-----
ファイルが存在する場合、末尾に追加して書き込み
(openFileOutputで使用する場合)
MODE_WORLD_READABLEallow all other applications to have read access to the created file.  ※ドキュメントより
-----
他アプリの読み出しが可能
API≧17で非推奨(※1)
MODE_WORLD_WRITEABLEallow all other applications to have write access to the created file.  ※ドキュメントより
-----
他アプリの書き込みが可能
※1:非推奨の範囲で用いた場合、SecurityExceptionを発行

「MODE_WORLD_READABLE/WRITEABLE」を用いると、作成したファイルはサンドボックスの外に出されてしまいます。必ず、「MODE_PRIVATE(デフォルト)」を用いて下さい。

# pwd
/data/user/0/パッケージ名/files
# ls -l *
-rw-rw---- u0_a58   u0_a58   6 2025-07-14 01:57 sample_Private.txt        ... MODE_PRIVATEを指定
-rw-rw-r-- u0_a58   u0_a58   6 2025-07-14 01:57 sample_WorldReadable.txt  ... MODE_WORLD_READABLEを指定
-rw-rw--w- u0_a58   u0_a58   6 2025-07-14 01:57 sample_WorldWriteable.txt ... MODE_WORLD_WRITEABLEを指定
       ↑↑ Otherのファイルパーミッションが付く
	   
※エミュレータ(API21)で確認

API≧17で非推奨になっているので、極めて古い端末に対応することが無ければ、無縁かも知れません。

スポンサーリンク

関連記事:

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