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

查看:420
本文介绍了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?

加载"按钮的代码:

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 :Sudoku puzzles/hard001.txt flg = 0x1}}到活动{com.example.sudokusolver/com.example.sudokusolver.MainActivity}:java.io.FileNotFoundException:/document/0000-0000:Sudoku puzzles/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云端硬盘流式传输,也可以直接从互联网上下载而无需您的应用知道这正在发生):

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天全站免登陆