Android M write to SD Card - Permission Denied

余生长醉 提交于 2019-12-18 03:04:39

问题


I'm trying to copy file from within my application to the SD card, but I get the error eacces (permission denied). The OS is Android M and I have allowed runtime Storage permissions (checked in app info). I have also set the uses-permission in AndroidManifest.xml

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

Doesn't work if I copy to SD card

Source: data/user/0/com.example.myapp/cache/SomeFile.txt
Destination: /storage/1032-2568/SomeFolder/
Error: java.io.FileNotFoundException: /storage/1032-2568/SomeFolder/SomeFile.txt: open failed: EACCES (Permission denied)

Works if I copy to internal storage

Source: data/user/0/com.example.myapp/cache/SomeFile.txt
Destination: /storage/emulated/0/SomeFolder/

Code to copy file from source to destination

/*
 * Below are the parameters I have tried
 *
 * inputPath - data/user/0/com.example.myapp/cache or data/user/0/com.example.myapp/cache/
 * inputFile - /SomeFile.txt or SomeFile.txt
 * outputPath - /storage/1032-2568/SomeFolder/ or /storage/1032-2568/SomeFolder
 */
public static void copyFile(String inputPath, String inputFile, String outputPath) {

    InputStream in = null;
    OutputStream out = null;
    try {

        //create output directory if it doesn't exist
        File dir = new File (outputPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        in = new FileInputStream(inputPath + inputFile);
        out = new FileOutputStream(outputPath + inputFile);

        byte[] buffer = new byte[1024];
        int read;
        while ((read = in.read(buffer)) != -1) {
            out.write(buffer, 0, read);
        }
        in.close();


        // write the output file (You have now copied the file)
        out.flush();
        out.close();
    }
    catch (FileNotFoundException fnfe1) {
        /* I get the error here */
        Log.e("tag", fnfe1.getMessage());
    }
    catch (Exception e) {
        Log.e("tag", e.getMessage());
    }
}

ES File Explorer

I saw that ES File Explorer also cannot write anything on the SD Card on Redmi devices. Here's a video with solution. Following the steps worked for ES Explorer on my device. Can this be done programmatically?


回答1:


As suggested by @CommonsWare here we have to use the new Storage Access Framework provided by android and will have to take permission from user to write SD card file as you said this is already written in the File Manager Application ES File Explorer.

Here is the code for Letting the user choose the "SD card" :

startActivityForResult(new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), requestCode);

which will look somewhat like this :

And get the Document path in pickedDirand pass further in your copyFile block and use this path for writing the file :

public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
    if (resultCode != RESULT_OK)
        return;
    else {
        Uri treeUri = resultData.getData();
        DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
        grantUriPermission(getPackageName(), treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        copyFile(sdCard.toString(), "/File.txt", path + "/new", pickedDir);
    }
}


public void copyFile(String inputPath, String inputFile, String outputPath, DocumentFile pickedDir) {

    InputStream in = null;
    OutputStream out = null;
    try {

        //create output directory if it doesn't exist
        File dir = new File(outputPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        in = new FileInputStream(inputPath + inputFile);
        //out = new FileOutputStream(outputPath + inputFile);

        DocumentFile file = pickedDir.createFile("//MIME type", outputPath);
        out = getContentResolver().openOutputStream(file.getUri());

        byte[] buffer = new byte[1024];
        int read;
        while ((read = in.read(buffer)) != -1) {
            out.write(buffer, 0, read);
        }
        in.close();


        // write the output file (You have now copied the file)
        out.flush();
        out.close();
    } catch (FileNotFoundException fnfe1) {
    /* I get the error here */
        Log.e("tag", fnfe1.getMessage());
    } catch (Exception e) {
        Log.e("tag", e.getMessage());
    }
}



回答2:


You need to add permission request run time in Android 6.0 (API Level 23) and up, here is the official docs

This is the code for WRITE_EXTERNAL_STORAGE

if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
    Log.d(TAG,"Permission is granted");

    return true;
}

Ask for permission else like this

ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);



回答3:


I can see that you are copying the entire content of one file and trying to write the same to another file. I could suggest a better way to do this :

Assuming that you already checked for file existence

StringWriter temp=new StringWriter();
        try{
            FileInputStream fis=new FileInputStream(inputFile+inputPath);
            int i;
            while((i=fis.read())!=-1)
            {
                temp.write((char)i);
            }
            fis.close();
            FileOutputStream fos = new FileOutputStream(outputPath, false);  // true or false based on opening mode as appending or writing
            fos.write(temp.toString(rs1).getBytes());
            fos.close();
        }
        catch (Exception e){}

This code worked for my app...Let me know if this is working for you or not..




回答4:


I have also got that problem but i solved by use the request the permission in run time and after forcefully give the permission.After the permission in App info of Android device. after declare the permission in manifest =>go to setting of your device => go to app info => go to permission => and finally allow the permission . just remember i just talking about after api level 22 means from marshmallow.




回答5:


Its seems the runtime permission are implemented correctly but the issues seems from the device If you are using Redmi than you have to manually allow the permission of specific app in Redmi security settings This link shows how to enable permission in redmi security




回答6:


After Android 4.3 on some devices, you can't get direct write access to FileSystem on SDcard.

You should use storage access framework for that.




回答7:


You can't copy or Delete files & Folder on external storage using third party app. like [file explorer].

It's data policy updated after KITKAT Version.

If only allow on system apps. So you can use an original file explorer (Come from ROM).

IF you need to use 3rd party app then ROOT your device. (Root permission is required)



来源:https://stackoverflow.com/questions/43066117/android-m-write-to-sd-card-permission-denied

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!