Many apps require access to the filesystem for accessing databases, reading content, and many other reasons.
There are two main areas for storing files: internal storage and external storage. Making use of the internal storage or app sandbox is very easy:
string sandbox = FilesDir.AbsolutePath;
string file = Path.Combine(sandbox, "myFile.txt"); bool exists = File.Exists(file); File.WriteAllText(file, "this is my value"); string value = File.ReadAllText(file);
string cache = CacheDir.AbsolutePath;
Using the external storage only has a few extra requirements. Typically, the way external storage is used is the same as the way internal storage is used, except that we have a different root folder:
[assembly: UsesPermission( Manifest.Permission.WriteExternalStorage)] [assembly: UsesPermission(Manifest.Permission.ReadExternalStorage)]
bool writeable = Android.OS.Environment.ExternalStorageState == Android.OS.Environment.MediaMounted; bool readable = writeable || Android.OS.Environment.ExternalStorageState == Android.OS.Environment.MediaMountedReadOnly;
string external = GetExternalFilesDir(null).AbsolutePath; string externalCache = ExternalCacheDir.AbsolutePath;
string downloadsDir = Android.OS.Environment.GetExternalStoragePublicDirectory( Android.OS.Environment.DirectoryDownloads) .AbsolutePath;
long freeSpace = FilesDir.FreeSpace; long totalSpace = GetExternalFilesDir(null).TotalSpace;
Working with the Android filesystem is similar to using the file systems on any .NET-supported platform. We can make use of all the features in .NET, as well as many of the Java features. However, Android does not allow access to all file locations on the device, especially the system locations or other app sandboxes.
Usually an app will access its own internal sandbox location obtained from FilesDir
and possibly the app cache location obtained from CacheDir
. Files saved to the internal storage are private to our app and neither other apps nor the user can access them.
When the user uninstalls our app, the internal files are removed automatically. In addition, the user may remove them through the device settings screens. As a result, we must first check whether a file exists before trying to read it.
Access to the external storage is no different but requires app permissions. Starting from Android 4.4, these permissions are not required if the only external access is through the GetExternalFilesDir()
method and the ExternalCacheDir
property. External files are visible to the user, especially if the files connect it to a computer as a USB mass storage device.
Files saved to the cache, whether internal via CacheDir
or external via ExternalCacheDir
, are meant to be temporary. Android may delete these files when the device starts to run out of free space or if the app is uninstalled. However, we should not rely on the system to clean up these files and maintain the cache ourselves.
It is very important to remember that external storage may become unavailable if the user mounts the external storage on a computer or removes the media. As a result, it is essential to check the availability of the external storage before use. In the Android.OS
namespace, the Environment
type contains the properties, methods, and other types used to determine the state of the external storage. The ExternalStorageState
property may be MediaMounted
, which is writeable, or MediaMountedReadOnly
, which is read only.
There are special public locations that are used by Android to hold the user's downloads—photos, music, and other files. These locations are obtained by passing the desired directory constant to the GetExternalStoragePublicDirectory()
method on Environment
.
We can see how much free space is available by using the FreeSpace
or TotalSpace
properties on the Java File
objects, such as the result from the FilesDir
property. The values returned aren't the exact space available, but a representation of how much free space can be available. If there is a few extra MB over the size to be saved, then it is probably OK to continue.
The external storage may not actually be the SD card but rather a section of the device's internal memory marked as external.
The actual SD card can be accessed using the result of GetExternalFilesDirs()
or ContextCompat.GetExternalFilesDir()
, which is an array of the external storage mediums available, one of which will be the actual SD card. Similarly for the cache, the locations are found in the result of GetExternalCacheDir()
or ContextCompat.GetExternalCacheDir()
.