【问题标题】:Access permission denied to external file on Android 10Android 10 上外部文件的访问权限被拒绝
【发布时间】:2020-11-20 03:20:59
【问题描述】:

我的应用是 targetSdkVersion = 29

我拍照并保存在路径:

src = /storage/emulated/0/DCIM/Camera/IMG_20201120_091943.jpg

然后我想使用 FileInputStream/FileOutputStream 将此图像复制到内部存储。虽然,我的应用程序有 WRITE/READ 存储权限,但是当我编码时

InputStream inputStream = FileInputStream(src)

我收到了 FileNotFoundException(打开失败:EACCES 权限被拒绝)。

有人有同样的问题吗?

注意:我不想通过使用选项 AndroidManifest.xml 来解决这个问题,因为它是临时的

android:requestLegacyExternalStorage="true"

【问题讨论】:

  • I don't want to fix this problem by using a option AndroidManifest.xml because it is temp 不。一点也不。将来它将保留并可用于 Android 10 设备。 Android 11 限制较少。但我想知道如何将文件保存到该路径,然后无法从中读取。
  • I take a photo and it save at path: 看来您并没有为此使用您的应用程序,而只是使用了相机应用程序。你应该自己说的。之后,您使用 Gallery 应用程序找到该路径。你应该告诉我们的。您只是在代码中硬编码了该路径。

标签: android


【解决方案1】:

当您的 targetSdkVersion >= 29 时,您必须使用 ScopedStorage,请参阅文档:https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage

所以简短的回答是你不能真正做到这一点。如果您的 targetSdkVersion 为 29,您应该使用 MediaStore API 来编写共享存储(“/storage/emulated/0/DCIM/Camera/IMG_20201120_091943.jpg”不是您的应用私有的,因此适用规则)

以下是使用 MediaStoreApi 将图像插入用户图像的方法: https://stackoverflow.com/a/56990305/5601663

此外,如果您真的只是想保存文件,以便它仅在您的应用程序中可用,那么您不需要使用 MediaStoreApi,请参阅这篇文章,了解如何在您的应用程序私有目录中保存: https://medium.com/@maksymilian.wojcik/android-saving-files-in-internal-storage-image-from-byte-array-etc-dd7d1b86d309

编辑:您当然可以在清单中使用 requestLegacyExternalStorage 标志,但您已经说过您不想使用它

Edit2:我现在看到您想从共享存储中读取。这也行不通,因为如果您的targetSdkVersion >= 29,您需要使用存储访问框架或媒体存储从那里读取。因此,对于这种情况,请按照此处所述的说明进行操作:https://developer.android.com/training/data-storage/use-cases#import-image-media

【讨论】:

    【解决方案2】:

    在 Android 10 上你不能使用 File API 访问共享存储中的文件,不幸的是,Android doc 对此并不一致,你可以找到它here 思考

    要解决此问题,请在 Android 10 上使用 Uri API,尽管这在 Android 11 前版中不是问题

    val uri = ContentUris.withAppendedId(MediaStore.Image.Media.EXTERNAL_CONTENT_URI, id)
    
    applicationContext.contentResolver.openInputStream(uri).use { stream ->
       // do your thing here
    }
    

    注意:您仍然可以对您的应用拥有的任何文件使用 File API

    【讨论】:

      【解决方案3】:

      我使用 FileInputStream/FileOutputStream 详细展示我的代码

      src = /storage/emulated/0/DCIM/Camera/IMG_20201120_091943.jpg

      dst = /storage/emulated/0/Android/data/my_app/files/Pictures/IMG_20201118_113434.jpg

      src 是保存照片的地方,dst 是我想将文件 src 复制到这里的地方

      public void copy(String src, String dst) {
              try {
                  BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(src));
                  OutputStream outPutStream = new FileOutputStream(dst);
                  int len;
                  byte[] buf = new byte[1024];
                  while ((len = bufferedInputStream.read(buf)) > 0) {
                      outPutStream.write(buf, 0, len);
                  }
      
                  outPutStream.flush();
                  outPutStream.close();
                  bufferedInputStream.close();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      

      FileNotFoundException (open failed: EACCES permission denied) at line:

      BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(src));

      【讨论】:

      • 请不要发布您的代码作为答案。删除此答案,然后在帖子的额外代码块中发布您的 cide
      猜你喜欢
      • 2021-09-16
      • 1970-01-01
      • 2014-08-10
      • 1970-01-01
      • 2010-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多