0

I'm trying to read a file from external storage /some/path/somefile.txt

In the manifest I have <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

When I click button to try to read file that was picked by ActivityResultContracts.OpenDocument() I am getting

java.io.FileNotFoundException: /document/primary:some/path/somefile.txt: open failed: ENOENT (No such file or directory)

Here is my code:

@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun ReadFileScreen() {
  val readPermissionState = rememberPermissionState(
    android.Manifest.permission.READ_EXTERNAL_STORAGE
  )
  val pickedFileUriState = remember { mutableStateOf<Uri?>(null) }
  val launcher =
    rememberLauncherForActivityResult(contract = ActivityResultContracts.OpenDocument()) { result ->
      pickedFileUriState.value = result
    }
  Column {
    Button(onClick = readPermissionState::launchPermissionRequest) {
      Text("request read permission")
    }
    PermissionRequired(readPermissionState, {}, {}) {
      Button(onClick = { launcher.launch(arrayOf("*/*")) }
      ) {
        Text("pick file")
      }
      if (pickedFileUriState.value != null) Button(onClick = { readTextFile(pickedFileUriState.value!!) }
      ) {
        Text("read file")
      }
    }
  }
}

fun readTextFile(uri: Uri) {
  try {
    val text = File(uri.path).readText()
    println(text)
  } catch (e: Exception) {
    e.printStackTrace()
  }
}
Tom Berghuis
  • 491
  • 3
  • 10
  • 26
  • 1
    The whole point of using `OpenDocument` is that you don't **need** any runtime permissions at all to access the **Uri** that is returned. Have you read the [guide for accessing the Uri you've received](https://developer.android.com/training/data-storage/shared/documents-files#input_stream)? – ianhanniballake Oct 22 '21 at 04:58
  • @ianhanniballake Thanks for the link, I will read that now, still new to android dev – Tom Berghuis Oct 22 '21 at 05:01

1 Answers1

0

Thanks to @ianhanniballake the link taught me the correct way to access the file picked by user.

Here is the code I came up with:

@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun ReadFileScreen() {
  val context = LocalContext.current
  val pickedFileUriState = remember { mutableStateOf<Uri?>(null) }
  val launcher =
    rememberLauncherForActivityResult(contract = ActivityResultContracts.OpenDocument()) { result ->
      pickedFileUriState.value = result
    }
  Column {
    Button(onClick = { launcher.launch(arrayOf("*/*")) }
    ) {
      Text("pick file")
    }
    if (pickedFileUriState.value != null)
      Button(onClick = {
        readTextFromUri(context, pickedFileUriState.value!!)
      }
      ) {
        Text("read file")
      }
  }
}

private fun readTextFromUri(context: Context, uri: Uri) {
  try {
    val stringBuilder = StringBuilder()
    context.contentResolver.openInputStream(uri)?.use { inputStream ->
      BufferedReader(InputStreamReader(inputStream)).use { reader ->
        var line: String? = reader.readLine()
        while (line != null) {
          stringBuilder.append(line)
          line = reader.readLine()
        }
      }
    }
    val text = stringBuilder.toString()
    Log.d("xxx", "text $text")
  } catch (e: IOException) {
    e.printStackTrace()
  }
}
Tom Berghuis
  • 491
  • 3
  • 10
  • 26