Android Kotlin:使用从文件选择器中选择的文件名获取 FileNotFoundException? [英] Android Kotlin: Getting a FileNotFoundException with filename chosen from file picker?

查看:41
本文介绍了Android Kotlin:使用从文件选择器中选择的文件名获取 FileNotFoundException?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个 Android 应用程序,其中一项功能是让用户选择要打开的文件(我想打开纯文本 .txt 文件).我之前使用 Java 开发过 Android 应用,但对于这个应用,我使用的是 Kotlin,这是我第一次使用 Kotlin.

I'm working on an Android application where one of the features is to let the user choose a file to open (I'm wanting to open a plain text .txt file). I've worked on Android apps before with Java, but for this one, I'm using Kotlin, and it's my first time using Kotlin.

我目前让应用显示一个文件选择器,让用户点击他们想要打开的文件.然后我尝试使用 File 对象打开文件并执行 forEachLine 循环.但出于某种原因,它抛出一个 java.io.FileNotFoundException (没有这样的文件或目录)与从文件选择器中选择的文件.我不确定出了什么问题,如果我必须做一些转换来转换文件路径?

I currently have the app display a file chooser and let the user tap the file they want to open. Then I'm trying to use a File object to open the file and do a forEachLine loop. But for some reason, it's throwing a java.io.FileNotFoundException (No such file or directory) with the file chosen from the file picker. I'm not sure what's wrong, and if I have to do some conversion to convert the file path?

我的加载"按钮的代码:

The code for my 'load' button:

val btn_load: Button = findViewById<Button>(R.id.btn_load_puzzle)
    btn_load.setOnClickListener {
        val intent = Intent()
            .setType("*/*")
            .setAction(Intent.ACTION_GET_CONTENT)

        startActivityForResult(Intent.createChooser(intent, "Select a file"), 111)
    }

我的响应文件选择的函数:

My function to respond to the file selection:

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

    // Selected a file to load
    if ((requestCode == 111) && (resultCode == RESULT_OK)) {
        val selectedFilename = data?.data //The uri with the location of the file
        if (selectedFilename != null) {
            val filenameURIStr = selectedFilename.toString()
            if (filenameURIStr.endsWith(".txt", true)) {
                val msg = "Chosen file: " + filenameURIStr
                val toast = Toast.makeText(applicationContext, msg, Toast.LENGTH_SHORT)
                toast.show()
                File(selectedFilename.getPath()).forEachLine {
                    val toast = Toast.makeText(applicationContext, it, Toast.LENGTH_SHORT)
                    toast.show()
                }
            }
            else {
                val msg = "The chosen file is not a .txt file!"
                val toast = Toast.makeText(applicationContext, msg, Toast.LENGTH_LONG)
                toast.show()
            }
        }
        else {
            val msg = "Null filename data received!"
            val toast = Toast.makeText(applicationContext, msg, Toast.LENGTH_LONG)
            toast.show()
        }
    }
}

在创建 File 对象以执行 forEachLine 循环的行上抛出 FileNotFound 异常:

The FileNotFound exception is thrown on the line where it creates the File object to do the forEachLine loop:

java.lang.RuntimeException: 未能传递结果 ResultInfo{who=null, request=111, result=-1, data=Intent { dat=content://com.android.externalstorage.documents/document/0000-0000:数独拼图/hard001.txt flg=0x1 }} 到活动 {com.example.sudokusolver/com.example.sudokusolver.MainActivity}: java.io.FileNotFoundException:/document/0000-0000:Sudoku拼图/hard001.txt (没有那个文件或目录)

java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=111, result=-1, data=Intent { dat=content://com.android.externalstorage.documents/document/0000-0000:Sudoku puzzles/hard001.txt flg=0x1 }} to activity {com.example.sudokusolver/com.example.sudokusolver.MainActivity}: java.io.FileNotFoundException: /document/0000-0000:Sudoku puzzles/hard001.txt (No such file or directory)

推荐答案

您没有收到文件路径,而是收到了 Uri.您必须使用基于 Uri 的 API,例如 ContentResolver.openInputStream() 访问 Uri 的内容,因为 Android 不授予您的应用直接 File访问底层文件(它也可以从 Google Drive 流式传输或直接从互联网下载,而您的应用程序并不知道正在发生这种情况):

You did not receive a file path, you received a Uri. You have to use Uri based APIs such as ContentResolver.openInputStream() to access the contents at that Uri as Android does not grant your app direct File access to the underlying file (it could also be streamed from Google Drive or downloaded directly from the internet without your app being aware that this is happening):

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

    // Selected a file to load
    if ((requestCode == 111) && (resultCode == RESULT_OK)) {
        val selectedFilename = data?.data //The uri with the location of the file
        if (selectedFilename != null) {
            contentResolver.openInputStream(selectedFilename)?.bufferedReader()?.forEachLine {
                val toast = Toast.makeText(applicationContext, it, Toast.LENGTH_SHORT)
                toast.show()
            }
        } else {
            val msg = "Null filename data received!"
            val toast = Toast.makeText(applicationContext, msg, Toast.LENGTH_LONG)
            toast.show()
        }
    }
}

这里我们可以假设我们通过将正确的 mime 类型传递给我们的请求来获得正确格式的内容(因为没有要求文本文件完全以 .txt 扩展名作为一部分其路径):

Here we can assume we get contents of the proper format by passing in the proper mime type to our request (as there is no requirement that a text file end in exactly the .txt extension as part of its path):

val intent = Intent()
    .setType("text/*")
    .setAction(Intent.ACTION_GET_CONTENT)

startActivityForResult(Intent.createChooser(intent, "Select a file"), 111)

这将自动使任何非文本文件无法选择.

Which will automatically make any non text file unable to be selected.

这篇关于Android Kotlin:使用从文件选择器中选择的文件名获取 FileNotFoundException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆