Handling Files

Most programmers, early on, learn how to read and write files. File I/O has been a staple of computer programming for decades. And, on Android, you can read and write files, much as you can with other operating systems.

The biggest difference in Android is where you can read and write files. That is quite a bit different than what you may be used to. And, increasingly, Google is pushing developers away from files entirely, steering us in the direction of the Storage Access Framework, as we saw in the chapter on content.

In this chapter, we will explore where we can read and write files.

The Three Types of File Storage

File storage locations in Android break down into three main types: internal, external, and removable.

Internal Storage

A user will think that “internal storage” refers to what they get when they plug their phone into a desktop via a USB cable. From the standpoint of the Android SDK, though, that is really external storage.

Internal storage, from the Android SDK’s perspective, refers to portions of the on-board flash that are both:

The only way that the user will interact with internal storage is through your app.

We have already worked a bit with internal storage: SharedPreferences are on internal storage. Later, when we examine Room, its databases are stored on internal storage by default. In terms of standard Java/Kotlin file I/O code, you find your internal storage locations via methods on Context. The two most common of those methods are:

External Storage

What the user thinks is “internal storage” is really “external storage” in the terms used by the Android SDK documentation. There are two main sets of locations on external storage that you can use: app-specific locations, and the overall shared portions of external storage.

App-Specific

There are methods on Context named getExternalFilesDir() and getExternalCacheDir(). These return locations on external storage that are unique for your app. And, as with their getFilesDir()/getCacheDir() counterparts, the “cache” ones are eligible to be cleared by the OS to free up disk space.

Unlike getFilesDir() and getCacheDir(), though, all locations on external storage can be accessed by the user and may be able to be accessed by other apps on the device. However, getExternalFilesDir() and getExternalCacheDir() are locations that are unique for your app — if you put things there, other apps should not accidentally overwrite or otherwise modify them.

Also, unlike getFilesDir() and getCacheDir(), getExternalFilesDir() and getExternalCacheDir() take a parameter. Typically, you pass in null.

Shared

Apps running on Android 9.0 and older can work with external storage overall via methods on the Environment class. In particular:

These locations are visible to the user and may be visible to other apps. And, since they are common and shared, other apps are more likely to manipulate files that you place here. At the same time, you may be able to manipulate the files of other apps, or files placed here by the user.

On newer versions of Android, these methods are deprecated, and you will not have access to them by default. Google is trying to steer you to the Storage Access Framework as an alternative.

Those location identifiers on Environment, such as DIRECTORY_DOWNLOADS, can also be passed to getExternalFilesDir() and getExternalCacheDir(), to get access to an app-specific directory on external storage for that type of material.

Removable Storage

Removable storage refers to micro SD cards, USB thumb drives, or anything else that the device supports that can be physically removed by the user, without breaking their phone.

For several years, Android had no official support for removable storage. Nowadays, not only does the Storage Access Framework work with it, but there are methods on Context that let you get to app-specific directories on removable storage. Calling getExternalFilesDirs(), getExternalCacheDirs(), or getExternalMediaDirs() (note the plural method names) will return an array of File objects representing directories. The first element in that array will be a location on external storage – in the case of getExternalFilesDirs() and getExternalCacheDirs(), it should be the same location as you get from calling getExternalFilesDir() and getExternalCacheDir(). If the array has 2+ elements, all but the first will point to an app-specific directory on some removable medium. You can read and write files here, create subdirectories, etc.


Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.