384

I am getting

open failed: EACCES (Permission denied)

on the line OutputStream myOutput = new FileOutputStream(outFileName);

I checked the root, and I tried android.permission.WRITE_EXTERNAL_STORAGE.

How can I fix this problem?

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

33 回答 33

371

谷歌在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 来说已经过时了。所以无论谁看到这个答案,请转到上面的链接并阅读说明。

于 2019-09-05T11:38:49.513 回答
363

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

于 2015-10-22T23:52:40.127 回答
248

我遇到了同样的问题......<uses-permission在错误的地方。这是正确的:

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

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

于 2012-03-28T12:33:39.987 回答
75

android:requestLegacyExternalStorage="true"添加到 Android Manifest 它在 SDK 29+
或迁移Android X后与 Android 10 (Q) 一起使用。

 <application
    android:name=".MyApplication"
    android:allowBackup="true"
    android:hardwareAccelerated="true"
    android:icon=""
    android:label=""
    android:largeHeap="true"
    android:supportsRtl=""
    android:theme=""
    android:requestLegacyExternalStorage="true">
于 2019-12-10T11:42:02.193 回答
59

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

于 2013-01-17T09:14:26.600 回答
53

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

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

于 2012-11-19T08:42:23.337 回答
30

请注意,解决方案:

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

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

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

这个视频可能会有很好的帮助。

于 2020-06-23T13:13:14.900 回答
30

我的问题是“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();
    }
}
于 2016-10-27T06:09:59.650 回答
19

我也有同样的经历。我发现,如果您转到Settings -> Application Manager -> Your App -> Permissions -> Enable Storage,它可以解决问题。

于 2018-02-08T06:26:46.843 回答
19

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

当我Environment.getExternalStorageDirectory()context.getExternalFilesDir(null).

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

在这里阅读更多。

于 2019-10-21T15:05:21.837 回答
14

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

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

于 2012-11-26T16:49:33.873 回答
13

我在运行 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,并具有读取权限。

于 2015-10-14T13:42:15.807 回答
9

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

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

于 2016-04-06T22:53:45.160 回答
9

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

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

对此:

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

更新:如评论中所述,正确的方法是:

File myFile= new File(Environment.getExternalStorageDirectory(), "newFile");
于 2016-12-17T21:51:40.873 回答
6

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

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

于 2014-07-19T16:52:14.323 回答
5

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

于 2012-01-13T17:09:24.927 回答
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>
于 2013-12-04T15:47:27.550 回答
5

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

于 2016-08-21T12:43:36.397 回答
5

也许答案是这样的:

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

于 2017-04-28T02:25:21.147 回答
4

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

于 2012-11-21T07:41:44.350 回答
4
Environment.getExternalStoragePublicDirectory();

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

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

这里的分辨率:

在 Android Q 中不推荐使用 getExternalStoragePublicDirectory

于 2019-07-19T11:58:35.400 回答
4

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

于 2018-12-25T20:31:38.823 回答
4

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

所以正确的方法是: -

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

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

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

另一种选择是 android:requestLegacyExternalStorage="true"按照manifest application tag建议,Uriel但它不是永久解决方案!

于 2020-04-01T12:38:37.310 回答
3

在我的例子中,我使用了一个文件选择器库,它返回了外部存储的路径,但它从/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
于 2017-08-28T19:51:48.583 回答
2

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

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

于 2015-01-06T10:56:20.360 回答
2

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

root@msm8996:/ # getenforce
getenforce
Enforcing
root@msm8996:/ # setenforce 0
setenforce 0
root@msm8996:/ # getenforce
getenforce
Permissive
于 2016-04-07T01:22:39.500 回答
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"/>
于 2016-10-21T09:53:03.193 回答
0

我有同样的问题(API >= 23)。

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

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

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

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

于 2017-05-09T07:19:27.633 回答
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.
        }   
    }
}
于 2018-04-11T15:53:31.350 回答
0

在我的情况下,错误出现在行上

      target.createNewFile();

因为我无法在 sd 卡上创建新文件,所以我不得不使用 DocumentFile 方法。

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

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

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

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

于 2019-04-07T03:46:57.943 回答
0

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

  1. 在我的情况下,根据范围存储在根目录文件中作为预先创建的文件目录//<图像/视频...根据要求>

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

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

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

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

于 2021-09-23T11:24:40.607 回答
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();
    }
于 2018-04-08T17:06:44.373 回答
0

我在小米设备(android 10)上遇到了同样的错误。以下代码解决了我的问题。库:Dexter(https://github.com/Karumi/Dexter)和图像选择器(https://github.com/Dhaval2404/ImagePicker

添加清单 ( android:requestLegacyExternalStorage="true")

    public void showPickImageSheet(AddImageModel model) {
    BottomSheetHelper.showPickImageSheet(this, new BottomSheetHelper.PickImageDialogListener() {
        @Override
        public void onChooseFromGalleryClicked(Dialog dialog) {
            selectedImagePickerPosition = model.getPosition();
            Dexter.withContext(OrderReviewActivity.this)                   .withPermissions(Manifest.permission.READ_EXTERNAL_STORAGE)
                    .withListener(new MultiplePermissionsListener() {
                        @Override
                        public void onPermissionsChecked(MultiplePermissionsReport report) {
                            if (report.areAllPermissionsGranted()) {
                                ImagePicker.with(OrderReviewActivity.this)
                                        .galleryOnly()
                                        .compress(512)
                                        .maxResultSize(852,480)
                               .start();
                            }
                        }

                        @Override
                        public void onPermissionRationaleShouldBeShown(List<PermissionRequest> list, PermissionToken permissionToken) {
                            permissionToken.continuePermissionRequest();
                        }

                    }).check();

            dialog.dismiss();
        }

        @Override
        public void onTakePhotoClicked(Dialog dialog) {
            selectedImagePickerPosition = model.getPosition();
            ImagePicker.with(OrderReviewActivity.this)
                    .cameraOnly()
                    .compress(512)
                    .maxResultSize(852,480)
                    .start();

            dialog.dismiss();
        }

        @Override
        public void onCancelButtonClicked(Dialog dialog) {
            dialog.dismiss();
        }
    });
}
于 2021-11-29T07:47:54.337 回答