Android上的例外'开放失败:EACCES(权限被拒绝)'

时间:2012-01-13 17:03:53

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

我正在

  

打开失败: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();
}

34 个答案:

答案 0 :(得分:310)

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

答案 1 :(得分:226)

我遇到了同样的问题...... <uses-permission出错了地方。这是对的:

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

uses-permission代码必须位于application代码之外。

答案 2 :(得分:57)

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

答案 3 :(得分:50)

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

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

答案 4 :(得分:47)

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/preview/privacy/scoped-storage

答案 5 :(得分:28)

我的问题是&#34; TargetApi(23)&#34;如果你的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();
    }
}

答案 6 :(得分:14)

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

答案 7 :(得分:13)

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

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

答案 8 :(得分:13)

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

import random

# Possible Range is [1-99], 1 inclusive to 99 inclusive
min_possible = 1
max_possible = 99

# Number of Guesses
max_guesses = 20

# Process
for i in xrange(max_guesses): # Loops through the process 'max_guesses' times

    # Program Takes a Guess
    guess = random.randint(min_possible, max_possible)
    print 'My guess is ' + str(guess)

    # Ask for User Feedback
    user_feedback = ''
    while not user_feedback in ['+', '-', '=']:
        user_feedback = raw_input('Is the number higher (+), lower (-), or equal (=) to my guess?')

    # Use the User Feedback
    if user_feedback == '+':
        min_possible = guess + 1 # B/c low end is inclusive
    elif user_feedback == '-':
        max_possible = guess - 1 # B/c high end is inclusive
    else:
        print 'I knew the answer was ' + str(guess)
        break

并且必须使用它来拍摄和存储用户照片。当我尝试在ImageLoader中加载相同的照片时,我收到<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18"/> 错误。解决方案是明确添加

(Permission denied)

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

答案 9 :(得分:12)

请注意解决方案:

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

这是临时的,迟早应将您的应用迁移为使用Scoped Storage

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

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

答案 10 :(得分:10)

Android Q 的解决方案:

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

答案 11 :(得分:9)

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

技巧:如果您的目标是22或更低版本,您的应用程序将在安装时请求所有权限,就像在Marshmallow下运行操作系统的任何设备上一样。如果您正在尝试使用模拟器,那么从Android 6.0开始,您需要明确地去设置 - &gt; apps-&gt; YOURAPP - &gt;权限,如果您已经提供权限,则更改权限。

答案 12 :(得分:6)

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

当USB存储开启时,外部存储读写权限不起作用。 只需关闭USB存储,并使用正确的权限,您就可以解决问题。

答案 13 :(得分:5)

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

答案 14 :(得分:5)

奇怪的是,在我的 newFile 之前加上斜线&#34; /&#34; 后,我的问题就解决了。我改变了这个:

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

到此:

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

答案 15 :(得分:5)

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

答案 16 :(得分: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>

答案 17 :(得分:4)

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

答案 18 :(得分:3)

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

答案 19 :(得分:3)

也许答案是这样的:

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

答案 20 :(得分:3)

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

答案 21 :(得分:3)

在我的情况下,我使用的是file picker library,它返回了外部存储路径,但它从/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

答案 22 :(得分:2)

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

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

答案 23 :(得分:2)

要将文件存储在应用目录的外部directory中,在API 29+上方受限。因此,要生成一个新文件或创建一个新文件,请使用您的应用程序目录,如下所示:-

所以正确的方法是:-

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

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

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

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

答案 24 :(得分:2)

我正在我的init.rc中的/ data /下创建一个文件夹(与Nexus 7上的aosp混在一起)并且确实存在这个问题。

事实证明,给予文件夹rw(666)权限是不够的,它必须是rwx(777)然后一切正常!

答案 25 :(得分: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"/>

答案 26 :(得分:0)

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

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

答案 27 :(得分: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();
    }

答案 28 :(得分:0)

以user462990的回答为基础

要在用户响应权限请求对话框时收到通知,请使用:( kotlin中的代码)

override fun onRequestPermissionsResult(requestCode: Int,
                           permissions: Array<String>, grantResults: IntArray) {
when (requestCode) {
    MY_PERMISSIONS_REQUEST_READ_CONTACTS -> {
        // If request is cancelled, the result arrays are empty.
        if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {

            // permission was granted, yay! Do the
            // contacts-related task you need to do.

        } else {

            // permission denied, boo! Disable the
            // functionality that depends on this permission.

        }
        return
    }

    // Add other 'when' lines to check for other
    // permissions this app might request.

    else -> {
        // Ignore all other requests.
    }
}

}

答案 29 :(得分:0)

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

      target.createNewFile();

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

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

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

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

也请参见此主题,          How to use the new SD card access API presented for Android 5.0 (Lollipop)?

答案 30 :(得分:0)

Environment.getExternalStoragePublicDirectory();

从Android 29开始使用不推荐使用的方法时,您将收到相同的错误:

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

此处的解决方法:

getExternalStoragePublicDirectory deprecated in Android Q

答案 31 :(得分:0)

我遇到了同样的问题(API&gt; = 23)。

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

我的解决方案是在Windows上安装正确的adb设备驱动程序。谷歌USB驱动程序无法用于我的设备。

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

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

答案 32 :(得分:0)

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

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

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

了解更多here

答案 33 :(得分:0)

Android 11 权限

在 manifest.xml 中声明 MANAGE_EXTERNAL_STORAGE 权限

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

在代码中检查管理存储的权限

 if (Environment.isExternalStorageManager()==false) {
     Uri uri = Uri.parse("package:" + BuildConfig.APPLICATION_ID);
     startActivity(new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri));
} else {
   // TO do.. open file picker intent
}

所有其他文件权限代码必须与android 11版本以下的代码相同