Instruction

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

In this lesson, you’ll learn how to read, write, and delete files in app-specific storage.

App-specific storage can be internal or external. Any files stored in app-specific storage are automatically deleted when the user uninstalls the app, ensuring the privacy and security of user data.

For internal storage, each app has a dedicated space in the device’s internal storage to save files. These files are private to the app, meaning other apps can’t access them. Internal storage is a secure place to store sensitive information or any data that your app needs to function but doesn’t need to be exposed to the user or other apps. These files persist across user sessions, even if your app is killed and restarted.

You can use external storage to save large files that are not intended to remain private to your app or to store other non-critical private files. Note that external storage can be unmounted or removed, so your app should handle these situations gracefully.

In the next section, you’ll learn how to read, write, and delete files in internal storage.

This section walks you through how to read, write, and delete files in internal storage. This is how to write to a file in internal storage:

fun writeTextFile(note: NoteEntity) {
  val directory = File(context.filesDir, DIRECTORY_NAME)
  if (!directory.exists()) {
    directory.mkdirs()
  }
  val file = File(directory, "${note.title}.txt")
  try {
    file.outputStream().use { outputStream ->
      outputStream.write(note.description.toByteArray())
    }
  } catch (e: IOException) {
    e.printStackTrace()
  }
}

In the code above, you write a NoteEntity object to a text file in the internal storage directory. You first create a directory in the internal storage directory if it doesn’t exist. Then, you create a file in this directory and write the note’s description to the file. You can view this file in the device’s internal storage directory. Go to Device Explorer in Android Studio, then navigate to data > data > your app’s package name > files > directory name > your file as shown below:

Internal Storage Directory
Internal Storage Directory

This is how you read from a file in internal storage:

fun readTextFile(title: String): String {
  val directory = File(context.filesDir, DIRECTORY_NAME)
  val file = File(directory, "$title.txt")
  return if (file.exists()) {
    try {
      file.inputStream().use { inputStream ->
        inputStream.bufferedReader().use { it.readText() }
      }
    } catch (e: IOException) {
      e.printStackTrace()
      ""
    }
  } else {
    ""
  }
}

In the code above, you’re reading a text file from the internal storage directory. You first get the internal storage directory where your files are stored and check if the specified file exists. If the file exists, you read the file and return the content as a String.

To delete a file in internal storage, you can use the delete() method on the File object as shown below:

fun deleteTextFile(title: String) {
  val directory = File(context.filesDir, DIRECTORY_NAME)
  val file = File(directory, "$title.txt")
  if (file.exists()) {
    file.delete()
  }
}

Note that we should wrap the operations in a try-catch block to handle any exceptions that may occur. This prevents the app from crashing by handling unexpected errors that may occur during file operations.

In the next section, you’ll learn how to perform the same operations on external storage.

This section walks you through how to read, write, and delete files in external storage. This is how to write to a file in external storage:

fun writeTextFile(note: NoteEntity) {
  if(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q &&
      ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    return
  }   
  if (!isExternalStorageWritable()) {
    return
  }
  val directory = File(context.getExternalFilesDir(null), DIRECTORY_NAME)
  if (!directory.exists()) {
    directory.mkdirs()
  }
  val file = File(directory, "${note.title}.txt")
  try {
    file.outputStream().use { outputStream ->
      outputStream.write(note.description.toByteArray())
    }
  } catch (e: IOException) {
    e.printStackTrace()
  }
}

Continuing with the NoteEntity object, you write a text file to the external storage directory. You start by checking if permission for WRITE_EXTERNAL_STORAGE is granted. This is needed for your app to work for devices with Android 9 and below.

Your note app minSdkVersion is 21, so you don’t need to check for permission, but it’s good to know how to do it. You then check if the external storage is writable. Notice that how you get the external storage directory using the context.getExternalFilesDir() method. This differs from how you access the internal storage directory. You also check if the directory exists and create it if it doesn’t. Lastly, you create a file in the directory and write the note’s description to the file. This is how the isExternalStorageWritable() function looks:

  private  fun isExternalStorageWritable(): Boolean =
    Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED

The function checks if the external storage is mounted since it isn’t guaranteed to always be available. You can view this file in the device’s internal storage directory in Android Studio. Go to Device Explorer, then navigate to Storage > emulated > 0 > Android > data > your app’s package name > files > directory name > your file as shown below:

External Storage Directory
External Storage Directory

To read the file from external storage:

fun readTextFile(title: String): String {
  if(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q &&
    ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    return
  }  
  if (!isExternalStorageReadable()) {
    return ""
  }
  val directory = File(context.getExternalFilesDir(null), DIRECTORY_NAME)
  val file = File(directory, "$title.txt")
  return if (file.exists()) {
    try {
      file.inputStream().use { inputStream ->
        inputStream.bufferedReader().use { it.readText() }
      }
    } catch (e: IOException) {
      e.printStackTrace()
      ""
    }
  } else {
    ""
  }
}

In the code above, you read a text file from the external storage directory. You start by checking if permission for READ_EXTERNAL_STORAGE is granted. This is because the permission is needed when your app needs to run on Android 9 or lower. You then check if the external storage is readable. You then get the external storage directory where your files are stored and read the specified file if the directory exists. Lastly, you return the content as a string. This is how the isExternalStorageReadable() function looks:

private fun isExternalStorageReadable(): Boolean =
  Environment.getExternalStorageState() in
    setOf(Environment.MEDIA_MOUNTED, Environment.MEDIA_MOUNTED_READ_ONLY)

This function checks if the external storage is either mounted or mounted read-only. This is because external storage may not always be available. To delete a file in external storage, you can use the delete() function on the File object as shown below:

fun deleteTextFile(title: String) {
  if(Build.VERSION.SDK_INT < Build.VERSION_CODES.Q &&
    ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    return
  }   
  if (!isExternalStorageWritable()) {
    return
  }
  val directory = File(context.getExternalFilesDir(null), DIRECTORY_NAME)
  val file = File(directory, "$title.txt")
  if (file.exists()) {
    file.delete()
  }
}

In the code above, you check if permission for WRITE_EXTERNAL_STORAGE is granted. You then proceed to check if the external storage is writable. Lastly, you get the external storage directory where the specified file is stored and delete the file.

See forum comments
Download course materials from Github
Previous: Introduction Next: Read & Write Files in Internal Storage