Android uses a file system that's
similar to disk-based file systems on other platforms. This page describes
how to work with the Android file system to read and write files with the File
APIs.
A File
object works well for reading or writing large amounts of data in
start-to-finish order without skipping around. For example, it's good for image files or
anything exchanged over a network.
The exact location of the where your files can be saved might vary across devices, so you should use the methods described on this page to access internal and external storage paths instead of using absolute file paths.
To view files on a device, you can log the file location provided by methods such as
File.getAbsolutePath()
, and then browse the device files
with Android Studio's Device File Explorer.
Choose internal or external storage
All Android devices have two file storage areas: "internal" and "external" storage. These names come from the early days of Android, when most devices offered built-in non-volatile memory (internal storage), plus a removable storage medium such as a micro SD card (external storage). Many devices now divide the permanent storage space into separate "internal" and "external" partitions. So even without a removable storage medium, these two storage spaces always exist, and the API behavior is the same regardless of whether the external storage is removable.
Because the external storage might be removable, there are some differences between these two options as follows.
Internal storage:
- It's always available.
- Files saved here are accessible by only your app.
- When the user uninstalls your app, the system removes all your app's files from internal storage.
Internal storage is best when you want to be sure that neither the user nor other apps can access your files.
External storage:
- It's not always available, because the user can mount the external storage as USB storage and in some cases remove it from the device.
- It's world-readable, so files saved here may be read outside of your control.
- When the user uninstalls your app, the system removes your app's files from here
only if you save them in the directory from
getExternalFilesDir()
.
External storage is the best place for files that don't require access restrictions and for files that you want to share with other apps or allow the user to access with a computer.
Tip: Although apps are installed onto the internal storage by
default, you can allow your app to be installed on external storage by specifying the
android:installLocation
attribute in your manifest. Users appreciate this option when the APK size is very large and
they have an external storage space that's larger than the internal storage. For more
information, see App Install Location.
Save a file on internal storage
Your app's internal storage directory is specified by your app's package name in a special location of the Android file system that can be accessed with the following APIs.
Note: Unlike the external storage directories, your app does not require any system permissions to read and write to the internal directories returned by these methods.
Write a file
When saving a file to internal storage, you can acquire the appropriate directory as a
File
by calling one of two methods:
getFilesDir()
- Returns a
File
representing an internal directory for your app. getCacheDir()
- Returns a
File
representing an internal directory for your app's temporary cache files. Be sure to delete each file once it is no longer needed and implement a reasonable size limit for the amount of memory you use at any given time, such as 1MB.Caution: If the system runs low on storage, it may delete your cache files without warning.
To create a new file in one of these directories, you can use the File()
constructor, passing the File
provided by one
of the above methods that specifies your internal storage directory. For example:
Kotlin
val file = File(context.filesDir, filename)
Java
File file = new File(context.getFilesDir(), filename);
Alternatively, you can call openFileOutput()
to get a FileOutputStream
that writes to a file in your internal directory. For example, here's
how to write some text to a file:
Kotlin
val filename = "myfile" val fileContents = "Hello world!" context.openFileOutput(filename, Context.MODE_PRIVATE).use { it.write(fileContents.toByteArray()) }
Java
String filename = "myfile"; String fileContents = "Hello world!"; FileOutputStream outputStream; try { outputStream = openFileOutput(filename, Context.MODE_PRIVATE); outputStream.write(fileContents.getBytes()); outputStream.close(); } catch (Exception e) { e.printStackTrace(); }
Notice that the openFileOutput()
method
requires a file mode parameter. Passing
MODE_PRIVATE
makes it private to your app.
The other mode options, MODE_WORLD_READABLE
and
MODE_WORLD_WRITEABLE
, have been deprecated since API level 17.
Starting with Android 7.0 (API level 24), Android throws a
SecurityException
if you use them. If your app needs to share private
files with other apps, you should instead use a FileProvider
with
the FLAG_GRANT_READ_URI_PERMISSION
.
For more information, see Sharing Files.
On Android 6.0 (API level 23) and lower, other apps can read your internal files if
you set the file mode to be world readable. However, the other app must know your app
package name and file names. Other apps cannot browse your internal directories and do not have read
or write access unless you explicitly set the files to be readable or writable. So as long as you
use MODE_PRIVATE
for your files on the internal storage, they are
never accessible to other apps.
Write a cache file
If you instead need to cache some files, you should use
createTempFile()
. For example, the following method extracts the
file name from a URL
and creates a file with that name
in your app's internal cache directory:
Kotlin
private fun getTempFile(context: Context, url: String): File? = Uri.parse(url)?.lastPathSegment?.let { filename -> File.createTempFile(filename, null, context.cacheDir) }
Java
private File getTempFile(Context context, String url) { File file; try { String fileName = Uri.parse(url).getLastPathSegment(); file = File.createTempFile(fileName, null, context.getCacheDir()); } catch (IOException e) { // Error while creating file } return file; }
Files created with createTempFile()
are placed in a cache
directory that's private to your app. You should regularly delete the
files you no longer need.
Caution: If the system runs low on storage, it may delete your cache files without warning, so make sure you check for the existence of your cache files before reading them.
Open an existing file
To read an existing file, call openFileInput(name)
, passing the name of the file.
You can get an array of all your app's file names by calling
fileList()
.
Tip: If you need to package a file in your app that is accessible at
install time, save the file in your project's res/raw/
directory. You can open these
files with openRawResource()
,
passing the R.raw.filename
resource ID. This
method returns an InputStream
that you can use to read the file.
You cannot write to the original file.
Open a directory
You can open a directory on the internal file system with the following methods:
getFilesDir()
- Returns a
File
representing the directory on the file system that's uniquely associated with your app. getDir(name, mode)
- Creates a new directory (or opens an existing directory)
within your app's unique file system directory. This new directory appears inside the directory
provided by
getFilesDir()
. getCacheDir()
- Returns a
File
representing the cache directory on the file system that's uniquely associated with your app. This directory is meant for temporary files, and it should be cleaned up regularly. The system may delete files there if it runs low on disk space, so make sure you check for the existence of your cache files before reading them.
To create a new file in one of these directories, you can use the
File()
constructor, passing the File
object
provided by one of the above methods that specifies your internal storage directory. For
example:
Kotlin
val directory = context.filesDir val file = File(directory, filename)
Java
File directory = context.getFilesDir(); File file = new File(directory, filename);
Save a file on external storage
Using the external storage is great for files that you want to share with other apps or allow the user to access with a computer.
After you request storage permissions and verify that storage is available, you can save two different types of files:
- Public files: Files that should be freely available to other apps and to the user. When the user uninstalls your app, these files should remain available to the user. For example, photos captured by your app or other downloaded files should be saved as public files.
- Private files: Files that rightfully belong to your app and will be deleted when the user uninstalls your app. Although these files are technically accessible by the user and other apps because they are on the external storage, they don't provide value to the user outside of your app.
Caution: The external storage might become unavailable if the user
removes the SD card or connects the device to a computer. And the files are still visible to the
user and other apps that have the READ_EXTERNAL_STORAGE
permission. So if your app's functionality depends on these
files or you need to completely restrict access, you
should instead write your files to the internal storage.
Request external storage permissions
To write to the public external storage, you must request the
WRITE_EXTERNAL_STORAGE
permission in your manifest file:
<manifest ...> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ... </manifest>
Note:
If your app uses the WRITE_EXTERNAL_STORAGE
permission, then it implicitly has permission to read the external storage as well.
If your app only needs
to read the external storage (but not write to it), then you need to declare the
READ_EXTERNAL_STORAGE
permission:
<manifest ...> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> ... </manifest>
Beginning with Android 4.4 (API level 19), reading or writing files in your app's private
external storage directory—accessed using
getExternalFilesDir()
—does not require
the READ_EXTERNAL_STORAGE
or WRITE_EXTERNAL_STORAGE
permissions. So if your app supports Android 4.3 (API level 18) and lower, and you want to access
only the private external storage directory, you should declare that the permission
be requested only on the lower versions of Android by adding the
maxSdkVersion
attribute:
<manifest ...> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" /> ... </manifest>
Verify that external storage is available
Because the external storage might be unavailable—such as when the user has mounted the
storage to a PC or has removed the SD card that provides the external storage—you
should always verify that the volume is available before accessing it. You can query the external
storage state by calling getExternalStorageState()
. If the returned
state is MEDIA_MOUNTED
, then you can read and
write your files. If it's MEDIA_MOUNTED_READ_ONLY
, you can only
read the files.
For example, the following methods are useful to determine the storage availability:
Kotlin
/* Checks if external storage is available for read and write */ fun isExternalStorageWritable(): Boolean { return Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED } /* Checks if external storage is available to at least read */ fun isExternalStorageReadable(): Boolean { return Environment.getExternalStorageState() in setOf(Environment.MEDIA_MOUNTED, Environment.MEDIA_MOUNTED_READ_ONLY) }
Java
/* Checks if external storage is available for read and write */ public boolean isExternalStorageWritable() { String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { return true; } return false; } /* Checks if external storage is available to at least read */ public boolean isExternalStorageReadable() { String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { return true; } return false; }
Save to a public directory
If you want to save public files on the external storage, use the
getExternalStoragePublicDirectory()
method to get a File
representing
the appropriate directory on the external storage. The method takes an argument specifying
the type of file you want to save so that they can be logically organized with other public
files, such as DIRECTORY_MUSIC
or
DIRECTORY_PICTURES
. For example:
Kotlin
fun getPublicAlbumStorageDir(albumName: String): File? { // Get the directory for the user's public pictures directory. val file = File(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES), albumName) if (!file?.mkdirs()) { Log.e(LOG_TAG, "Directory not created") } return file }
Java
public File getPublicAlbumStorageDir(String albumName) { // Get the directory for the user's public pictures directory. File file = new File(Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES), albumName); if (!file.mkdirs()) { Log.e(LOG_TAG, "Directory not created"); } return file; }
If you want to hide your files from the Media Scanner, include an empty file named
.nomedia
in your external files directory (note the dot
prefix in the filename). This prevents media scanner from reading your media
files and providing them to other apps through the MediaStore
content provider.
Save to a private directory
If you want to save files on external storage that are private to your app and not
accessible by the MediaStore
content provider, you can acquire a
directory that's used by only your app by calling
getExternalFilesDir()
and passing it a name
indicating the type of directory you'd like. Each directory created this way is added to a parent
directory that encapsulates all your app's external storage files, which the system deletes when the
user uninstalls your app.
Caution: Files on external storage are not always accessible, because users can mount the external storage to a computer for use as a storage device. So if you need to store files that are critical to your app's functionality, you should instead store them on internal storage.
For example, here's a method you can use to create a directory for an individual photo album:
Kotlin
fun getPrivateAlbumStorageDir(context: Context, albumName: String): File? { // Get the directory for the app's private pictures directory. val file = File(context.getExternalFilesDir( Environment.DIRECTORY_PICTURES), albumName) if (!file?.mkdirs()) { Log.e(LOG_TAG, "Directory not created") } return file }
Java
public File getPrivateAlbumStorageDir(Context context, String albumName) { // Get the directory for the app's private pictures directory. File file = new File(context.getExternalFilesDir( Environment.DIRECTORY_PICTURES), albumName); if (!file.mkdirs()) { Log.e(LOG_TAG, "Directory not created"); } return file; }
If none of the pre-defined sub-directory names suit your files, you can instead call
getExternalFilesDir()
and pass
null
. This returns the root directory for your app's private directory on the external
storage.
Remember that getExternalFilesDir()
creates a directory that is deleted when the user uninstalls your app.
If the files you're saving should remain available after the user uninstalls your
app—such as when your app captures photos and the user should keep those photos—you
should instead save the files to a public directory.
Regardless of whether you use getExternalStoragePublicDirectory()
for files that are shared or
getExternalFilesDir()
for files that are private to your app, it's important that you use
directory names provided by API constants like
DIRECTORY_PICTURES
. These directory names ensure
that the files are treated properly by the system. For instance, files saved in
DIRECTORY_RINGTONES
are categorized by the system media scanner as
ringtones instead of music.
Select between multiple storage locations
Sometimes, a device that allocates a partition of the internal memory for use as the external storage also provides an SD card slot. This means that the device has two different external storage directories, so you need to select which one to use when writing "private" files to the external storage.
Beginning with Android 4.4 (API level 19), you can access both locations by calling
getExternalFilesDirs()
, which returns
a File
array with entries for each storage location. The first entry in the array
is considered the primary external storage, and you should use that location unless it's full or
unavailable.
If your app supports Android 4.3 and lower, you should use the support library's
static method, ContextCompat.getExternalFilesDirs()
. This always returns a File
array, but if the
device is running Android 4.3 and lower, then it contains just one entry for the primary
external storage (if there's a second storage location, you cannot access it on Android 4.3 and
lower).
Query free space
If you know ahead of time how much data you're saving, you can find out
whether sufficient space is available without causing an IOException
by calling
getFreeSpace()
or getTotalSpace()
. These methods provide the
current available space and the
total space in the storage volume, respectively. This information is also useful to avoid filling
the storage volume above a certain threshold.
However, the system does not guarantee that you can write as many bytes as are
indicated by getFreeSpace()
. If the number returned is a
few MB more than the size of the data you want to save, or if the file system
is less than 90% full, then it's okay to proceed.
Otherwise, you probably shouldn't write to storage.
Note: You aren't required to check the amount of available space
before you save your file. You can instead try writing the file right away, then
catch an IOException
if one occurs. You may need to do
this if you don't know exactly how much space you need. For example, if you
change the file's encoding before you save it by converting a PNG image to
JPEG, you won't know the file's size beforehand.
Delete a file
You should always delete files that your app no longer need. The most straightforward way to
delete a file is to call delete()
on the File
object.
Kotlin
myFile.delete()
Java
myFile.delete();
If the file is saved on internal storage, you can also ask the Context
to locate and delete a file by calling deleteFile()
:
Kotlin
myContext.deleteFile(fileName)
Java
myContext.deleteFile(fileName);
Note: When the user uninstalls your app, the Android system deletes the following:
- All files you saved on internal storage.
- All files you saved external storage using
getExternalFilesDir()
.
However, you should manually delete all cached files created with
getCacheDir()
on a regular basis and also regularly delete
other files you no longer need.