【问题标题】:Android上的异常“打开失败:EACCES(权限被拒绝)”
【发布时间】:2012-02-09 21:07:19
【问题描述】:

我得到了

打开失败:EACCES (Permission denied)

上线OutputStream myOutput = new FileOutputStream(outFileName);

我检查了根目录,并尝试了android.permission.WRITE_EXTERNAL_STORAGE

我该如何解决这个问题?

try {
    InputStream myInput;

    myInput = getAssets().open("XXX.db");

    // Path to the just created empty db
    String outFileName = "/data/data/XX/databases/"
            + "XXX.db";

    // Open the empty db as the output stream
    OutputStream myOutput = new FileOutputStream(outFileName);

    // Transfer bytes from the inputfile to the outputfile
    byte[] buffer = new byte[1024];
    int length;
    while ((length = myInput.read(buffer)) > 0) {
        myOutput.write(buffer, 0, length);
    }

    // Close the streams
    myOutput.flush();
    myOutput.close();
    myInput.close();
    buffer = null;
    outFileName = null;
}
catch (IOException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}

【问题讨论】:

  • 我在 Android 平板电脑上遇到了同样的问题,但我的情况可能很独特,所以我在评论中报告了我的解决方案。当应用程序尝试访问具有 50 多个 xml 文件的目录 /data/data/myapp/foo 时发生错误。由于错误,该应用程序没有清理文件夹。删除一些旧文件后,错误消失了。我不知道为什么。这可能是通用 Android 设备的问题。

标签: android android-5.0-lollipop android-permissions android-storage


【解决方案1】:

Google 在 Android Q 上有一项新功能:用于外部存储的过滤视图。对此的快速修复是将此代码添加到 AndroidManifest.xml 文件中:

<manifest ... >
    <!-- This attribute is "false" by default on apps targeting Android Q. -->
    <application android:requestLegacyExternalStorage="true" ... >
     ...
    </application>
</manifest>

您可以在此处阅读更多信息:https://developer.android.com/training/data-storage/use-cases

编辑:我开始被否决,因为这个答案对于 Android 11 来说已经过时了。所以看到这个答案的人请转到上面的链接并阅读说明。

【讨论】:

  • @Billy 我注意到它只发生在具有 api 29 的设备上。所以我搜索了文件提供程序中的更改
  • 您先生,为我节省了很多时间。对于 Q 中的开发人员来说,很多事情已经成为一种痛苦。我认为这个答案应该作为一个单独的问题发布,并且值得更多的支持。
  • 你救了我。我正在尽一切努力解决它。我猜问题出在 Android 10 上,你只用一行就解决了,谢谢 (y)
  • 从 Android 11 开始这不再有效
  • @RoshanaPitigala 需要为 android 11 做什么链接?
【解决方案2】:

对于 API 23+,您需要请求读/写权限,即使它们已经在您的清单中。

// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
};

/**
 * Checks if the app has permission to write to device storage
 *
 * If the app does not has permission then the user will be prompted to grant permissions
 *
 * @param activity
 */
public static void verifyStoragePermissions(Activity activity) {
    // Check if we have write permission
    int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);

    if (permission != PackageManager.PERMISSION_GRANTED) {
        // We don't have permission so prompt the user
        ActivityCompat.requestPermissions(
                activity,
                PERMISSIONS_STORAGE,
                REQUEST_EXTERNAL_STORAGE
        );
    }
}

AndroidManifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

有关请求 API 23+ 权限的官方文档,请查看https://developer.android.com/training/permissions/requesting.html

【讨论】:

  • 只是为了澄清,为了使它工作,活动必须处理活动权限请求响应。有关详细信息,请参阅developer.android.com/training/permissions/…
  • 方便的链接,这里有解释和例子inthecheesefactory.com/blog/…
  • 这不是坏事吗?在用户体验方面。
  • 但是我在哪里使用它呢?例如,如果我想拍照,我必须在 startActivityForResult 之前运行 verifyStoragePermissions,还是在 onActivityResult 运行?这真的让我很困惑。
  • 谢谢这解决了我的问题。请注意:如果有人无法解析“Manifest.permission”,您只需导入“import android.Manifest”。
【解决方案3】:

我遇到了同样的问题...&lt;uses-permission 放错地方了。没错:

 <manifest>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        ...
        <application>
            ...
            <activity> 
                ...
            </activity>
        </application>
    </manifest> 

uses-permission 标签必须在application 标签之外。

【讨论】:

  • 就是uses-permission需要在应用之外
  • 我收到警告:“&lt;uses-permission&gt; 标签出现在&lt;application&gt; 标签之后”
  • 警告在 android 4.4.4 中不要使用参数android:maxSdkVersion="18"。它正在生成此异常
  • 此权限从 API 级别 19 开始强制执行。在 API 级别 19 之前,此权限未强制执行,所有应用仍然可以从外部存储读取。
  • 在 API 29 之后,您将需要这个:medium.com/@sriramaripirala/…
【解决方案4】:

android:requestLegacyExternalStorage="true" 添加到 Android Manifest 它适用于 SDK 29+ 的 Android 10 (Q)
或在迁移 Android X 之后。

 <application
    android:name=".MyApplication"
    android:allowBackup="true"
    android:hardwareAccelerated="true"
    android:icon=""
    android:label=""
    android:largeHeap="true"
    android:supportsRtl=""
    android:theme=""
    android:requestLegacyExternalStorage="true">

【讨论】:

【解决方案5】:

我在模拟器中运行应用程序时曾观察到这一点。在模拟器设置中,您需要正确指定外部存储(“SD 卡”)的大小。默认情况下,“外部存储”字段为空,这可能意味着没有这样的设备并且即使在清单中授予权限也会抛出 EACCES。

【讨论】:

    【解决方案6】:

    除了所有答案之外,请确保您没有将手机用作 USB 存储设备。

    我在启用 USB 存储模式的 HTC Sensation 上遇到了同样的问题。我仍然可以调试/运行应用程序,但无法保存到外部存储。

    【讨论】:

    • 谢谢,尽管我在运行时向用户请求了权限。这个错误发生在模拟器上。
    • 当我连接三星 Galaxy S6 设备时,它首先给出一个选项“允许访问设备数据”,“拒绝”或“允许”,并且从通知栏中我得到一个选项使用 USB 1 . MTP 2. PTP 3. MIDI 设备 4. 充电。选择哪一个?
    【解决方案7】:

    我的问题是“TargetApi(23)”,如果您的 minSdkVersion 低于 23,则需要它。

    所以,我有以下 sn-p 的请求权限

    protected boolean shouldAskPermissions() {
        return (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1);
    }
    
    @TargetApi(23)
    protected void askPermissions() {
        String[] permissions = {
                "android.permission.READ_EXTERNAL_STORAGE",
                "android.permission.WRITE_EXTERNAL_STORAGE"
        };
        int requestCode = 200;
        requestPermissions(permissions, requestCode);
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    // ...
        if (shouldAskPermissions()) {
            askPermissions();
        }
    }
    

    【讨论】:

      【解决方案8】:

      注意解决方案:

      <application ...
          android:requestLegacyExternalStorage="true" ... >
      

      是临时的,迟早你的应用应该被迁移到使用Scoped Storage

      在 Android 10 中,您可以使用建议的解决方案绕过系统限制,但在 Android 11 (R) it is mandatory to use scoped storage 中,如果您继续使用旧逻辑,您的应用可能会崩溃!

      This video 可能是一个很好的帮助。

      【讨论】:

        【解决方案9】:

        我也有同样的经历。我发现如果你去设置 -> 应用程序管理器 -> 你的应用程序 -> 权限 -> 启用存储,它解决了这个问题。

        【讨论】:

        • 我找不到这个部分?
        【解决方案10】:

        Android 10 (API 29) 引入了范围存储。更改清单以请求旧版存储并不是一个长期的解决方案。

        当我用context.getExternalFilesDir(null) 替换我以前的Environment.getExternalStorageDirectory() 实例(API 29 已弃用)时,我解决了这个问题。

        请注意,如果存储位置不可用,context.getExternalFilesDir(type) 可能会返回 null,因此请务必在检查您是否具有外部权限时进行检查。

        阅读更多here

        【讨论】:

          【解决方案11】:

          事实证明,这是一个愚蠢的错误,因为我的手机仍然连接到台式电脑,却没有意识到这一点。

          所以我不得不关闭 USB 连接,一切正常。

          【讨论】:

          • 也为我工作。但为什么它会起作用?不将 USB 连接到 PC 有什么不同。
          • 好问题。我从来没有进一步调查过这个。我猜在您连接设备的那一刻,系统会出现一个写锁(因此它可能会在您的计算机上模拟 USB 设备)。也许这是为了避免数据不一致。不过不确定。
          【解决方案12】:

          我在运行 CM 12.1 的三星 Galaxy Note 3 上遇到了同样的问题。对我来说,问题是我有

          <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
              android:maxSdkVersion="18"/>
          

          并且不得不用它来拍摄和存储用户照片。当我尝试在 ImageLoader 中加载这些相同的照片时,我收到了 (Permission denied) 错误。解决方案是显式添加

          <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
          

          因为上述权限仅将写入权限限制在 API 版本 18 以内,并具有读取权限。

          【讨论】:

          • 没有帮助我!值得一试!谢谢。
          【解决方案13】:

          除了所有答案之外,如果客户端使用的是 Android 6.0,Android 会为 (Marshmallow) 添加新的permission model

          技巧:如果您的目标是 22 或更低版本,您的应用程序将在安装时请求所有权限,就像在运行低于 Marshmallow 的操作系统的任何设备上一样。如果您在模拟器上尝试,那么从 android 6.0 开始,您需要显式转到设置->应用程序-> YOURAPP -> 权限并更改权限(如果您提供了任何权限)。

          【讨论】:

          • 难以置信,我花了 2 天时间试图弄清楚这一点。每次我觉得在 Android 上运行顺利时,就会发生这样的事情。
          【解决方案14】:

          奇怪的是,在我的 newFile 之前加上一个斜杠 "/" 后,我的问题就解决了。我改变了这个:

          File myFile= new File(Environment.getExternalStorageDirectory() + "newFile");
          

          到这里:

          File myFile= new File(Environment.getExternalStorageDirectory() + "/newFile");
          

          更新: 如 cmets 中所述,正确的做法是:

          File myFile= new File(Environment.getExternalStorageDirectory(), "newFile");
          

          【讨论】:

          • 这里没什么奇怪的。在第一行中,您尝试在与包含外部存储目录的目录相同的目录中创建一个文件。即 /storage/.../somethingnewfile 而不是 /storage/.../something/newfile
          • @Stéphane 如果您查看广泛的答案,错误本身就很奇怪。
          • 正确的做法是使用 File(dir, file) cosntructor
          • @NickCardoso 您也可以使用文件(字符串路径名)。看起来你在这里没有得到重点。问题不在于如何使用 File 类。该线程中的答案范围显示了此错误的误导性以及解决该错误的可能方法有多少。在我的情况下,错误是缺少斜线。有些人发现它很有用。当然,您可以使用自己的方法访问文件。继续并发布您的答案。它可能会解决某人的问题。
          • 我想备份@NickCardoso...当我使用 File(pathname) 构造函数时出现错误...使用 File(dir, file) 构造函数一切正常...
          【解决方案15】:

          我遇到了同样的问题,但没有任何建议有帮助。但我发现了一个有趣的原因,在物理设备上,Galaxy Tab

          当 USB 存储打开时,外部存储读取和写入权限没有任何影响。 只需关闭 USB 存储设备,并使用正确的权限,即可解决问题。

          【讨论】:

          • 该死,我只花了大约 3 个小时来解决这个问题。此外,我不得不重新启动设备并且它确实有效。非常感谢
          【解决方案16】:

          我希望/data 以下的所有内容都属于“内部存储”。但是,您应该可以写信给/sdcard

          【讨论】:

          • 我也试过 。还是一样。
          • /data-partition 通常对试图访问普通文件的普通(非 root)用户进行写保护。对于内部存储,有专门的方法可以做到这一点,特别是如果您想访问数据库。 Android developer pages 应该可以帮助您解决这个问题。
          【解决方案17】:

          更改/system/etc/permission/platform.xml 中的权限属性
          和组需要如下提及。

          <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">
              <group android:gid="sdcard_rw" />
              <group android:gid="media_rw" />    
          </uses-permission>
          

          【讨论】:

          • platform.xml 已被锁定,通过 adb shell 尝试此操作,但需要 ADB 允许我用于 mod 的任何脚本。
          • 失败。让我的设备进入启动循环。
          【解决方案18】:

          我在 Galaxy S5 (android 6.0.1) 上尝试在 DCIM/camera 文件夹中写入图像时遇到了同样的错误,我发现只有这个文件夹受到限制。我可以简单地写入 DCIM/任何文件夹,但不能写入相机。 这应该是基于品牌的限制/定制。

          【讨论】:

            【解决方案19】:

            也许答案是这样的:

            在API >= 23台设备上,如果你安装了应用程序(应用程序不是系统应用程序),你应该在“设置-应用程序”中检查存储权限,每个应用程序都有权限列表,你应该检查它!试试

            【讨论】:

              【解决方案20】:

              当你的应用属于系统应用时,它不能访问SD卡。

              【讨论】:

                【解决方案21】:

                请记住,即使您在清单中设置了所有正确的权限: 允许第三方应用程序在您的外部卡上写入的唯一位置是“他们自己的目录” (即 /sdcard/Android/data/) 试图写到其他任何地方:你会得到异常: EACCES(权限被拒绝)

                【讨论】:

                  【解决方案22】:
                  Environment.getExternalStoragePublicDirectory();
                  

                  从 Android 29 开始使用此已弃用的方法时,您将收到相同的错误:

                  java.io.FileNotFoundException: open failed: EACCES (Permission denied)

                  这里的解决方法:

                  getExternalStoragePublicDirectory deprecated in Android Q

                  【讨论】:

                    【解决方案23】:

                    将文件存储在与应用程序目录无关的directory 中是限制API 29+ 之上的。因此,要生成新文件或创建新文件,请使用您的应用程序目录,如下所示:-

                    所以正确的做法是:-

                    val file = File(appContext.applicationInfo.dataDir + File.separator + "anyRandomFileName/")
                    

                    您可以将任何数据写入此生成的文件!

                    上面的file 是可访问的,而throw any exception 是不可访问的,因为它位于您自己的开发的应用程序的 目录中。

                    另一个选项是manifest application tag 中的android:requestLegacyExternalStorage="true" Uriel 建议,但它不是永久解决方案!

                    【讨论】:

                      【解决方案24】:

                      在我的例子中,我使用了 file picker library,它返回了外部存储的路径,但它从 /root/ 开始。即使在运行时授予 WRITE_EXTERNAL_STORAGE 权限,我仍然收到错误 EACCES (Permission denied)
                      所以使用Environment.getExternalStorageDirectory() 来获取外部存储的正确路径。

                      示例:
                      不能写:/root/storage/emulated/0/newfile.txt
                      可以写:/storage/emulated/0/newfile.txt

                      boolean externalStorageWritable = isExternalStorageWritable();
                      File file = new File(filePath);
                      boolean canWrite = file.canWrite();
                      boolean isFile = file.isFile();
                      long usableSpace = file.getUsableSpace();
                      
                      Log.d(TAG, "externalStorageWritable: " + externalStorageWritable);
                      Log.d(TAG, "filePath: " + filePath);
                      Log.d(TAG, "canWrite: " + canWrite);
                      Log.d(TAG, "isFile: " + isFile);
                      Log.d(TAG, "usableSpace: " + usableSpace);
                      
                      /* Checks if external storage is available for read and write */
                      public boolean isExternalStorageWritable() {
                          String state = Environment.getExternalStorageState();
                          if (Environment.MEDIA_MOUNTED.equals(state)) {
                              return true;
                          }
                          return false;
                      }
                      

                      输出 1:

                      externalStorageWritable: true
                      filePath: /root/storage/emulated/0/newfile.txt
                      isFile: false
                      usableSpace: 0
                      

                      输出 2:

                      externalStorageWritable: true
                      filePath: /storage/emulated/0/newfile.txt
                      isFile: true
                      usableSpace: 1331007488
                      

                      【讨论】:

                      • 我遇到了同样的问题。从路径中删除 root 部分解决了我的问题。
                      【解决方案25】:

                      我正在我的 init.rc 中的 /data/ 下创建一个文件夹(在 Nexus 7 上使用 aosp),并且遇到了这个问题。

                      原来给文件夹rw(666)权限是不够的,必须是rwx(777)才行!

                      【讨论】:

                        【解决方案26】:

                        如果您有一个 root 设备,则可以通过以下 adb 命令绕过 6.0 后强制执行的存储权限:

                        root@msm8996:/ # getenforce
                        getenforce
                        Enforcing
                        root@msm8996:/ # setenforce 0
                        setenforce 0
                        root@msm8996:/ # getenforce
                        getenforce
                        Permissive
                        

                        【讨论】:

                          【解决方案27】:

                          在清单中添加权限。

                          <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
                          <uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
                          <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
                          

                          【讨论】:

                          • 没有权限android.permission.READ_INTERNAL_STORAGE
                          【解决方案28】:

                          我使用下面的过程来处理android 11和targetapi30的情况

                          1. 在我的情况下,根据范围存储在根目录文件中作为预先创建的文件目录//

                          2. 复制选取的文件并在从我的外部存储中选取时将文件复制到缓存目录中

                          3. 然后一次上传(点击我的发送/上传按钮)将文件从缓存目录复制到我的作用域存储目录,然后执行我的上传过程

                          使用此解决方案,因为有时在 Play 商店中上传应用程序会生成 MANAGE_EXTERNAL_STORAGE 权限的警告,有时在我的情况下被 Play 商店拒绝。

                          由于我们使用目标 API 30,因此我们无法将文件从内部存储共享或转发到应用程序

                          【讨论】:

                            【解决方案29】:

                            我遇到了同样的问题(API >= 23)。

                            解决方案https://stackoverflow.com/a/13569364/1729501 对我有用,但断开应用程序进行调试是不切实际的。

                            我的解决方案是在 Windows 上安装适当的 adb 设备驱动程序。谷歌 USB 驱动程序不适用于我的设备。

                            第 1 步:为您的设备品牌下载 adb 驱动程序。

                            步骤 2:转到设备管理器 -> 其他设备 -> 查找带有单词“adb”的条目 -> 选择更新驱动程序 -> 在步骤 1 中提供位置

                            【讨论】:

                              【解决方案30】:

                              添加 gradle 依赖项

                              implementation 'com.karumi:dexter:4.2.0'
                              

                              在您的主要活动中添加以下代码。

                              import com.karumi.dexter.Dexter;
                              import com.karumi.dexter.MultiplePermissionsReport;
                              import com.karumi.dexter.PermissionToken;
                              import com.karumi.dexter.listener.PermissionRequest;
                              import com.karumi.dexter.listener.multi.MultiplePermissionsListener;
                                  @Override
                              protected void onCreate(Bundle savedInstanceState) {
                                  super.onCreate(savedInstanceState);
                                  setContentView(R.layout.activity_splash);
                              
                                  new Handler().postDelayed(new Runnable() {
                                          @Override
                                          public void run() {
                              
                              
                                              checkMermission();
                                          }
                                      }, 4000);
                                  }
                              
                                  private void checkMermission(){
                                      Dexter.withActivity(this)
                                              .withPermissions(
                                                      android.Manifest.permission.READ_EXTERNAL_STORAGE,
                                                      android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
                                                      android.Manifest.permission.ACCESS_NETWORK_STATE,
                                                      Manifest.permission.INTERNET
                                              ).withListener(new MultiplePermissionsListener() {
                                          @Override
                                          public void onPermissionsChecked(MultiplePermissionsReport report) {
                                              if (report.isAnyPermissionPermanentlyDenied()){
                                                  checkMermission();
                                              } else if (report.areAllPermissionsGranted()){
                                                  // copy some things
                                              } else {
                                                  checkMermission();
                                              }
                              
                                          }
                                          @Override
                                          public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
                                              token.continuePermissionRequest();
                                          }
                                      }).check();
                                  }
                              

                              【讨论】:

                                猜你喜欢
                                • 2016-06-14
                                • 2014-02-07
                                • 1970-01-01
                                • 2021-12-23
                                • 2021-07-02
                                • 2016-01-06
                                相关资源
                                最近更新 更多