27

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?

Sahil Khanna
  • 4,262
  • 8
  • 47
  • 72

7 Answers7

27

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 :

enter image description here

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());
    }
}
shadygoneinsane
  • 2,226
  • 1
  • 24
  • 47
9

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);
Junaid Hafeez
  • 1,618
  • 1
  • 16
  • 25
2

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.

Peter
  • 587
  • 6
  • 16
1

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

Burhanuddin Rashid
  • 5,260
  • 6
  • 34
  • 51
1

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.

Rostyslav Roshak
  • 3,859
  • 2
  • 35
  • 56
0

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

Bharat
  • 1,044
  • 15
  • 34
  • Can you paste some more code like your activity file from which you are trying to operate on file....So I can help you better – Bharat Mar 28 '17 at 09:51
  • You said you gave permission from app info.If you are doing like this then you have to give permission every time you clear your app data.So what I'm guessing is like you tried to copy file from internal storage and then you cleared app's data.So it has lost its access to storage and this time without giving permission you might have tried to access the storage . So you are getting the error – Bharat Mar 28 '17 at 09:56
  • I have allowed Storage permissions using RunTime permissions. And I'm not clearing data. – Sahil Khanna Mar 28 '17 at 10:12
  • Please show your file handling code otherwise how can we predict bro ? – Bharat Mar 28 '17 at 12:56
  • bro I've changed my answer check it and let me know – Bharat Mar 28 '17 at 15:59
  • It didn't work. I'm using Xiaomi Redmi Note 3 with Android M. Also check the ES File Explorer thing in the question. See if you can help. – Sahil Khanna Mar 30 '17 at 06:10
0

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)

Jigar Patel
  • 1,550
  • 2
  • 13
  • 29