Search code examples
androidbase64android-file

How to get base64 from file's URI?


In general, my task is to get base64 from chosen file. In order to open File Browser, I call following function:

private fun showFileBrowser() {
    val intent = Intent(Intent.ACTION_GET_CONTENT)
    intent.setType("*/*")
    startActivityForResult(intent, FILE_CHOOSE_REQUEST_CODE)
}

It is successfully opened. When some file is chosen, onActivityResult is called. Here it is:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)

    if (requestCode == FILE_CHOOSE_REQUEST_CODE) {
        // not that data.data is Uri
        if(data != null && data.data != null) {
            val encodedBase64 = getBase64FromPath(data.data.path)
            print(encodedBase64)
        }


    }

}

Here is how I convert File to base64:

 private fun getBase64FromPath(path: String): String {

    try {
        val bytes = File(path).readBytes()

        return Base64.encodeToString(bytes, Base64.DEFAULT)
    } catch (error: IOException) {
        error.printStackTrace() // This exception always occurs 
    }

}

Seems like I do everything right, but I get FileNotFoundException. I don't know what is the reason for this. I didn't add any permission, because I don't to write anything to scared, I just want a user to choose a file, I will convert it to base64 and send it to the server. So, what is the problem this my code?


Solution

  • my task is to get base64 from chosen file

    Your code has little to do with files. ACTION_GET_CONTENT is not limited to files on the device, let alone files on the filesystem that you can access.

    When some file is chosen, onActivityResult is called

    You get a Uri via onActivityResult(). A Uri is not a file, and getPath() on a Uri only has meaning if the scheme of that Uri is file. Most Uri values will have a scheme of content.

    Replace your function with:

    private fun getBase64ForUriAndPossiblyCrash(uri: Uri): String {
    
        try {
            val bytes = contentResolver.openInputStream(uri).readBytes()
    
            return Base64.encodeToString(bytes, Base64.DEFAULT)
        } catch (error: IOException) {
            error.printStackTrace() // This exception always occurs 
        }
    

    The AndPossiblyCrash portion of the function name is because you are going to run out of memory if the content is too large. Also note that you are doing this work on the main application thread, so your UI will be frozen while you are reading this in.