安卓系统出现异常:'open failed: EACCES (Permission denied)'

414

我遇到了以下问题:

打开失败:EACCES(Permission denied)

出错在这一行:OutputStream myOutput = new FileOutputStream(outFileName);

我已经检查了root权限,并尝试添加了 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设备的问题。 - Hong
这个帖子解决了我的问题:https://dev59.com/B1wX5IYBdhLWcg3wjwJZ - partho
36个回答

4

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


4

请记住,即使您在清单中设置了所有正确的权限:

第三方应用程序仅允许在其自己的目录(即 /sdcard/Android/data/)上写入外部卡。

尝试写入其他任何地方都会导致异常:

EACCES(权限被拒绝)


4

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

2

如果您的设备已经获取了root权限,您可以通过以下adb命令绕过存储权限的6.0强制执行:

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

2

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

后来发现,仅给文件夹分配rw(666)权限是不够的,必须分配rwx(777)权限,然后一切都正常了!


你能给我看一下你是怎么读取数据的吗?我把权限设置为777,但仍然显示权限被拒绝的错误。 - Saman Sattari
1
抱歉,我已经多年没有接触安卓了,也没有任何记忆!或许你可以发一个新的问题? - lane

2
我在小米设备(Android 10)上遇到了相同的错误。以下代码解决了我的问题。 库:Dexter(https://github.com/Karumi/Dexter)和Image picker(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();
        }
    });
}

1
我使用以下步骤处理 Android 11 和 targetapi30 的情况:
  1. 按照范围存储的预创建文件目录,在我的情况下是在根目录 files//<Image/Video... 根据需求>

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

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

由于在上传应用程序时会生成 MANAGE_EXTERNAL_STORAGE 权限警告,并且有时会在我的情况下被 Play 商店拒绝,因此使用此解决方案。
另外,由于我们使用了 target API 30,因此无法从内部存储器共享或转发文件。

1

2022年 Kotlin 请求权限的方式:

private val writeStoragePermissionResult =
   registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->}

private fun askForStoragePermission(): Boolean =
   if (hasPermissions(
           requireContext(),
           Manifest.permission.READ_EXTERNAL_STORAGE,
           Manifest.permission.WRITE_EXTERNAL_STORAGE
       )
   ) {
       true
   } else {
       writeStoragePermissionResult.launch(
           arrayOf(
               Manifest.permission.READ_EXTERNAL_STORAGE,
               Manifest.permission.WRITE_EXTERNAL_STORAGE,
           )
       )
       false
   }

fun hasPermissions(context: Context, vararg permissions: String): Boolean = permissions.all {
    ActivityCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}

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

      target.createNewFile();

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

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

对于上述问题,可以通过以下方法解决:
    fos=context.getContentResolver().openOutputStream(documentFile.getUri());

请看这个帖子, 如何使用Android 5.0(棒棒糖)中提供的新SD卡访问API?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接