android kotlin:获取文件名从文件选择器中选择的filenotfoundexception?

epggiuax  于 2021-08-20  发布在  Java
关注(0)|答案(4)|浏览(650)

我正在开发一个android应用程序,其中一个功能是让用户选择要打开的文件(我想打开一个纯文本.txt文件)。我以前使用java开发过android应用程序,但这次我使用了kotlin,这是我第一次使用kotlin。
我目前让应用程序显示一个文件选择器,让用户点击他们想要打开的文件。然后我尝试使用一个file对象来打开文件并执行foreachline循环。但出于某种原因,它会抛出一个java.io.filenotfoundexception(没有这样的文件或目录),该文件是从文件选择器中选择的。我不确定出了什么问题,如果我必须做一些转换来转换文件路径?
“加载”按钮的代码:

  1. val btn_load: Button = findViewById<Button>(R.id.btn_load_puzzle)
  2. btn_load.setOnClickListener {
  3. val intent = Intent()
  4. .setType("*/*")
  5. .setAction(Intent.ACTION_GET_CONTENT)
  6. startActivityForResult(Intent.createChooser(intent, "Select a file"), 111)
  7. }

响应文件选择的my函数:

  1. override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
  2. super.onActivityResult(requestCode, resultCode, data)
  3. // Selected a file to load
  4. if ((requestCode == 111) && (resultCode == RESULT_OK)) {
  5. val selectedFilename = data?.data //The uri with the location of the file
  6. if (selectedFilename != null) {
  7. val filenameURIStr = selectedFilename.toString()
  8. if (filenameURIStr.endsWith(".txt", true)) {
  9. val msg = "Chosen file: " + filenameURIStr
  10. val toast = Toast.makeText(applicationContext, msg, Toast.LENGTH_SHORT)
  11. toast.show()
  12. File(selectedFilename.getPath()).forEachLine {
  13. val toast = Toast.makeText(applicationContext, it, Toast.LENGTH_SHORT)
  14. toast.show()
  15. }
  16. }
  17. else {
  18. val msg = "The chosen file is not a .txt file!"
  19. val toast = Toast.makeText(applicationContext, msg, Toast.LENGTH_LONG)
  20. toast.show()
  21. }
  22. }
  23. else {
  24. val msg = "Null filename data received!"
  25. val toast = Toast.makeText(applicationContext, msg, Toast.LENGTH_LONG)
  26. toast.show()
  27. }
  28. }
  29. }

filenotfound异常在创建file对象以执行foreachline循环的行上抛出:
java.lang.runtimeexception:传递结果resultinfo{who=null,request=111,result=-1,数据=意图{dat=content://com.android.externalstorage.documents/document/0000-0000:sudoku 拼图/hard001.txt flg=0x1}}到活动{com.example.sudokusolver/com.example.sudokusolver.mainactivity}:java.io.filenotfoundexception:/document/0000-0000:sudoku拼图/hard001.txt(没有这样的文件或目录)

cs7cruho

cs7cruho1#

您没有收到文件路径,而是收到了 Uri . 你必须使用 Uri 基于API的应用程序接口,如 ContentResolver.openInputStream() 访问当时的内容 Uri 因为android不会直接授予你的应用 File 访问基础文件(也可以从google drive流式传输或直接从internet下载,而您的应用程序不知道正在发生这种情况):

  1. override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
  2. super.onActivityResult(requestCode, resultCode, data)
  3. // Selected a file to load
  4. if ((requestCode == 111) && (resultCode == RESULT_OK)) {
  5. val selectedFilename = data?.data //The uri with the location of the file
  6. if (selectedFilename != null) {
  7. contentResolver.openInputStream(selectedFilename)?.bufferedReader()?.forEachLine {
  8. val toast = Toast.makeText(applicationContext, it, Toast.LENGTH_SHORT)
  9. toast.show()
  10. }
  11. } else {
  12. val msg = "Null filename data received!"
  13. val toast = Toast.makeText(applicationContext, msg, Toast.LENGTH_LONG)
  14. toast.show()
  15. }
  16. }
  17. }

在这里,我们可以假设通过向请求传递适当的mime类型来获得适当格式的内容(因为不要求文本文件以完全相同的格式结尾) .txt 扩展(作为其路径的一部分):

  1. val intent = Intent()
  2. .setType("text/*")
  3. .setAction(Intent.ACTION_GET_CONTENT)
  4. startActivityForResult(Intent.createChooser(intent, "Select a file"), 111)

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

展开查看全部
rjzwgtxy

rjzwgtxy2#

不能在计算机上打开java文件 ÙRI 转换为字符串后,uri的“路径”部分与物理文件位置没有关系。
使用 contentResolver 获取java FileDescriptor 要打开文件,请使用。

  1. val parcelFileDescriptor: ParcelFileDescriptor =
  2. contentResolver.openFileDescriptor(uri, "r")
  3. val fileDescriptor: FileDescriptor = parcelFileDescriptor.fileDescriptor

此方法与android 10兼容,在android 10中,非应用程序专用目录的文件路径不可用。
https://developer.android.com/training/data-storage/shared/documents-files

yqhsw0fo

yqhsw0fo3#

如果您在uri中获得“msf:”,请使用以下解决方案,其中我在应用缓存目录中创建了临时文件,并在完成任务后删除了相同的文件:

  1. if (id != null && id.startsWith("msf:")) {
  2. final File file = new File(mContext.getCacheDir(), Constant.TEMP_FILE + Objects.requireNonNull(mContext.getContentResolver().getType(imageUri)).split("/")[1]);
  3. try (final InputStream inputStream = mContext.getContentResolver().openInputStream(imageUri); OutputStream output = new FileOutputStream(file)) {
  4. final byte[] buffer = new byte[4 * 1024]; // or other buffer size
  5. int read;
  6. while ((read = inputStream.read(buffer)) != -1) {
  7. output.write(buffer, 0, read);
  8. }
  9. output.flush();
  10. return file;
  11. } catch (IOException ex) {
  12. ex.printStackTrace();
  13. }
  14. return null;
  15. }

我已经解决了这个问题,它对无国界医生100%有效。:)
完成工作后,还要删除临时文件:

  1. private void deleteTempFile() {
  2. final File[] files = requireContext().getCacheDir().listFiles();
  3. if (files != null) {
  4. for (final File file : files) {
  5. if (file.getName().contains(Constant.TEMP_FILE)) {
  6. file.delete();
  7. }
  8. }
  9. }
  10. }

这里的temp_文件值是“temp”

展开查看全部
kgsdhlau

kgsdhlau4#

根据其uri打开位图文件:

  1. private Bitmap getBitmapFromUri(Uri uri) throws IOException {
  2. ParcelFileDescriptor parcelFileDescriptor =
  3. getContentResolver().openFileDescriptor(uri, "r");
  4. FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
  5. Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
  6. parcelFileDescriptor.close();
  7. return image;
  8. }

相关问题