java.io.FileNotFoundException:(权限被拒绝)在 oreo android

java.io.FileNotFoundException: (Permission denied) in oreo android

以下代码用于在sdcard(外部存储)中创建的文件中写入联系人详细信息:

try {
                while (phones.isAfterLast() == false) {

                    String lookupKey = phones.getString(phones
                            .getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
                    Uri uri = Uri.withAppendedPath(
                            ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey);

                    AssetFileDescriptor fd;


                    fd = mContext.getContentResolver().openAssetFileDescriptor(uri, "r");
                    FileInputStream fis = fd.createInputStream();
                    byte[] buf = readBytes(fis);
                    fis.read(buf);
                    String VCard = new String(buf);
                    FileOutputStream mFileOutputStream = new FileOutputStream(
                            cpath, true);
                    mFileOutputStream.write(VCard.getBytes());
                    phones.moveToNext();
                }
            } catch (Exception e1) {
                Applog.e(TAG, e1);
                isOk = false;
            }

其中,cpath是我的文件在sd卡中的路径。

这里,我在线上遇到错误:

FileOutputStream mFileOutputStream = new FileOutputStream(
                            cpath, true);

我低于日志:-

java.io.FileNotFoundException: /storage/9016-4EF8/AllBackupDemo/cont20181031050512.vcf (Permission denied)
        at java.io.FileOutputStream.open0(Native Method)
        at java.io.FileOutputStream.open(FileOutputStream.java:287)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:223)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:142)

文档树选择代码:

private void triggerStorageAccessFramework() {
        startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), REQUEST_SAF_PERMISSION);
    }

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
//        Log.e(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data + ")");
        if (resultCode == RESULT_CANCELED) return;

        switch (requestCode) {
            case REQUEST_SAF_PERMISSION:{
                Uri treeUri = data.getData();
                if(treeUri != null){
                    session.setPrefURI(treeUri.toString());
                }
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                    getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                }
                toast(getString(R.string.permission_granted_saf));
                break;
            }
        }
    }

注意:

  1. 我只在 android oreo 版本中遇到此错误。它在牛轧糖中工作正常。
  2. 我已经授予了运行时权限并且在清单文件中也提到了。
  3. 我已经为文档文件权限实施了 SAF。

解法:

我分析并比较了我的代码和你的代码,发现你使用的所有代码都是一样的。

必须更改出现错误的行。此错误是由于使用了 FileOutputStream,这表明您正在从文件系统访问,而不是从 DocumentTree.

因此,而不是:

FileOutputStream mFileOutputStream = new FileOutputStream(
                        cpath, true);

尝试这样的事情:

try {
    OutputStream out = getContentResolver().openOutputStream(cpath.getUri());
    try {

        // Do whatever you wish to do.

    } finally {
        out.close();
    }

} catch (IOException e) {
    throw new RuntimeException("Something went wrong : " + e.getMessage(), e);
}

我不确定你的程序的实际流程,你可能想自己过一遍。但是,这肯定会给你一个继续前进的想法。

希望对您有所帮助。