Android上的异常“打开失败:EACCES(权限被拒绝)”


297

我正进入(状态

打开失败: 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平板电脑上遇到了同样的问题,但情况可能是独一无二的,因此我在此处发表评论并提出解决方案。当应用尝试访问目录/ data / data / myapp / foo(包含50个以上的xml文件)时,发生错误。由于存在错误,该应用未清除文件夹。删除一些旧文件后,错误消失了。我不知道为什么。这可能是通用Android设备的问题。

Answers:


236

我遇到了同样的问题... <uses-permission位置错误。这是对的:

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

uses-permission标签必须是外面application的标签。


2
它是使用权限需要在应用程序外部
user462990 2012年

3
我收到警告:“ <uses-permission>标签在<application>标签后出现”
mr5

11
警告在android 4.4.4中不要使用参数android:maxSdkVersion="18"。它产生了这个例外
guisantogui

1
此权限从API级别19开始强制执行。在API级别19之前,不强制执行此权限,并且所有应用仍然有权从外部存储读取。
Zar E Ahmer

1
我正在使用API​​ lvl 15,尝试将文件移动到OTG USB记忆棒时收到错误消息
Ravi Mehta

330

对于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


13
为了明确起见,为了使此工作正常进行,活动必须处理活动权限请求响应。详情请参阅developer.android.com/training/permissions/…
kldavis4 2015年

并提供了解释和例子便捷链接这里inthecheesefactory.com/blog/...
保罗·亚历山大

1
这不是一件坏事吗?关于用户体验。
M. Usman Khan

5
但是我在哪里使用呢?例如,如果我想拍照,是否必须在startActivityForResult之前或onActivityResult上运行verifyStoragePermissions?这真的让我感到困惑。
Kiwi Lee

3
谢谢你,这解决了我的问题。请注意:如果某人无法解决“ Manifest.permission”,则只需导入“ import android.Manifest”。
Oubaida AlQuraan

166

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/compatibility


@Billy我注意到它仅在具有api 29的设备上发生。因此,我搜索了文件提供程序中的更改
Uriel Frankel

最终让cloudtestingscreenshotter_lib.aar可以将此行添加到androidTest清单中,非常感谢您的发现。
bko

6
先生,您节省了我很多时间。对于Q的开发人员来说,很多事情已经变得很痛苦。我认为这个答案应该作为一个单独的问题发布,应该得到更多的支持。
sanjeev

我想详细了解这个小小的黑魔术,但不幸的是,该链接返回了404错误...无论如何,谢谢
SadSido

它发出警告,android:requestLegacyExternalStorage="true"这不会破坏较低版本的ryt吗?@UrielFrankel
Santanu Sur

58

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


51

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

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


谢谢男人,即使我在运行时已向用户请求权限。在模拟器上发生此错误。
锐边

1
当我连接Samsung Galaxy S6设备时,它首先提供带有“拒绝”或“允许”的选项“允许访问设备数据”,并且还从通知栏中获得了将USB用于1. MTP 2. PTP 3. MIDI的选项。设备4.充电。选择哪一个?
testingh '16

34

android:requestLegacyExternalStorage =“ true”添加到Android清单中。此版本可在SDK 10+
或更高版本的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">

哇,效果很好,这是我所寻求的答案,太好了,谢谢@rhaldar,您保存了我的一天
Ayush Katuwal

29

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

因此,我具有以下代码段的请求权限

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();
    }
}

28

Android Q解决方案:

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

你救了我的一天。授予了权限,但Glide无法读取图像,除非我设置了此项。
leegor '19

注意:Android 11将在2020年8月完全删除旧版访问,因此可以更好地升级文件访问以为您的应用使用存储访问框架(SAF)
dimib


13

原来,这是一个愚蠢的错误,因为我的手机仍连接到台式PC并没有意识到这一点。

因此,我不得不关闭USB连接,一切正常。


也为我工作。但是为什么行得通呢?不将USB连接到PC有什么区别。
user13107

好问题。我再也没有对此进行调查。我猜想在连接设备后系统就会有一个写锁(这样它就可以在您的计算机上模拟一个USB设备)。也许这是为了避免数据不一致。虽然不确定。
Tobias Reich


13

我在运行CM 12.1的Samsung 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,并因此具有读取权限。


没帮我!值得一试!谢谢。
Sakiboy '17

9

除了所有答案外,如果客户端使用的是Android 6.0,则Android 为(棉花糖)添加了新的权限模型

绝招:如果您的目标版本为22或更低版本,则您的应用程序将在安装时请求所有权限,就像在运行低于棉花糖的操作系统的任何设备上一样。如果您尝试使用仿真器,则从android 6.0起,您需要显式转到设置->应用程序-> YOURAPP->权限,并更改权限(如果已提供)。


2
真是难以置信,我花了2天的时间来弄清楚这一点。每当我感到Android上一切运行顺利时,就会发生这种情况。
Jaime Ivan Cervantes

7

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

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

对此:

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

1
这里没什么奇怪的。在第一行中,您尝试在与包含外部存储目录的目录相同的目录中创建文件。即/storage/.../somethingnewfile而不是/storage/.../something/newfile
斯特凡

@Stéphane如果您查看范围广泛的答案,则错误本身很奇怪。
达鲁什'17

3
正确的方法是使用File(dir,file)cosntructor
Nick Cardoso

@NickCardoso您还可以使用File(String pathname)。看来您在这里没弄明白重点。问题不在于如何使用File类。该主题的答案范围显示了此错误的误导性以及解决该错误的可能方式。就我而言,错误是缺少斜杠。有些人发现它很有用。当然,您可以使用自己的访问文件的方法。继续并发布您的答案。它可以解决某人的问题。
达鲁什

没有明白这一点。如果您使用正确的构造函数,则无需进行破解。添加我的评论的目的是,它可以帮助您以后因错误而误导的任何读者。这不是个人批评,不需要回复
Nick Cardoso

6

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

启用USB存储设备后,外部存储设备的读取和写入权限将无效。只需关闭USB存储器,并获得正确的权限,即可解决问题。


2
该死的,我只花了大约三个小时的时间。另外,我必须重新启动设备,它才能正常工作。非常感谢
crgarridos '16

5

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


5
我也尝试过<uses-permission android:name =“ android.permission.WRITE_INTERNAL_STORAGE” />。还是一样。
Mert 2012年

1
对于试图访问普通文件的普通(非root用户)用户,/ data-partition通常具有写保护。对于内部存储,有专门的方法可以执行此操作,尤其是在您要访问数据库时。在Android开发者页面应该可以帮助您在这个问题上。
烤箱

5

在您/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允许我使用的任何脚本。
约翰

失败。将我的设备放入引导循环。
Tobse '16

5

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


4

当您的应用程序属于系统应用程序时,它将无法访问SD卡。


4

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


3

也许答案是这样的:

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


3

在我的情况下,我使用的是文件选择器库,该将路径返回到外部存储,但它从开始/root/。即使在运行时授予WRITE_EXTERNAL_STORAGE权限,我仍然会收到错误EACCES(权限被拒绝)
所以用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从路径中删除零件解决了我的问题。
xabush


3

对于任何来自搜索结果并针对Android 10的用户:Android 10(API 29)会更改一些与存储相关的权限。

当我用替换以前的实例Environment.getExternalStorageDirectory()(API 29不推荐使用)时,我解决了该问题context.getExternalFilesDir(null)

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

在这里阅读更多。


2

我在init.rc中的/ data /下创建了一个文件夹(与Nexus 7上的aosp混为一谈),并且确实遇到了这个问题。

原来,授予文件夹rw(666)权限还不够,它必须是rwx(777),然后一切正常!


2

如果您通过以下adb命令拥有根设备,则可以绕过6.0版之后的存储权限强制实施:

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

1

在清单中添加权限。

<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"/>

3
没有权限android.permission.READ_INTERNAL_STORAGE
瑞恩- [R

0

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

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

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

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

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


0

添加权限后解决了我的问题

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

0

添加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();
    }

0

就我而言,错误出现在行上

      target.createNewFile();

由于无法在sd卡上创建新文件,因此必须使用DocumentFile方法。

      documentFile.createFile(mime, target.getName());

对于上述问题,可以使用这种方法解决问题,

    fos=context.getContentResolver().openOutputStream(documentFile.getUri());

也请参见此线程, 如何使用为Android 5.0(Lollipop)提供的新SD卡访问API?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.