10

I'm trying to save images from the apps local data folders to external storage. My manifest contains the following (before the manifest's application tags):

<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" />

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18"/>

When I try the following

try {
        InputStream in = new FileInputStream(filePath);
        File outPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        File outFile = new File(outPath, "mypicture.jpg");


        //try fails at this line
        OutputStream out = new FileOutputStream(outFile);

        byte[] buf = new byte[1024];
        int len;

        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }

        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;
} catch (IOException e) {
    e.printStackTrace();
}

I get this error:

java.io.FileNotFoundException: /storage/emulated/0/Pictures/mypicture.jpg: open failed: EACCES (Permission denied)

I've also tried a slightly different output path instead:

 String sdCardPath = Environment.getExternalStorageDirectory() + "/MyFolder";
 new File(sdCardPath).mkdirs();
 File outFile = new File(sdCardPath, "mypicture.jpg");

but that gives me an error too:

java.io.FileNotFoundException: /storage/emulated/0/MyFolder/mypicture.jpg: open failed: ENOENT (No such file or directory)

The device is running Android 4.4.2, so shouldn't need to request permissions at runtime (as far as I'm aware it can't request them).

Is there something else that could be missing in order to allow saving a file to external storage?

TheBestBigAl
  • 1,231
  • 1
  • 16
  • 42

4 Answers4

11

The cause of the issue was an external library pulled in via gradle which had its own manifest requesting <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18">

My own manifest only worked if maxSdkVersion="18" was NOT included, and so the manifest merger adding that param caused this error. My solution was to change my own manifest to:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="23" tools:replace="android:maxSdkVersion" />

I assume that the maxSdkVersion="18" meant that any devices running SDK 19-22 could not have this permission (with 23+ being able to request it at runtime).

TheBestBigAl
  • 1,231
  • 1
  • 16
  • 42
1

It shoudn't be necessary, but try to add this permission in you Manifest.

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

Sometimes Android trolls us.

Manza
  • 3,427
  • 4
  • 36
  • 57
0

In Android 6, you need to request permission at runtime. If you run on 4.4, still have that error, I think you have not create folder yet.

 String sdCardPath = Environment.getExternalStorageDirectory() + "/MyFolder";
 new File(sdCardPath) .mkdirs(); //create folders where write files
 File outFile = new File(sdCardPath, "mypicture.jpg");
RoShan Shan
  • 2,924
  • 1
  • 18
  • 38
  • I already have a line to create the folders as seen above: new File(sdCardPath).mkdirs(); Which doesn't seem to solve the problem. – TheBestBigAl Jan 09 '17 at 16:35
  • Oh. Srry my bag. Do you try to remove `android:maxSdkVersion="18"`. Or your directory is correct with your picture path `MyFolder\mypicture.jpg`? – RoShan Shan Jan 09 '17 at 16:42
  • I've tried both with and without maxSdkVersion, neither made a difference. I believe the path is correct, I've also tried putting mypicture.jpg directly into Environment.getExternalStorageDirectory() but had the same error. It's almost as if the WRITE_EXTERNAL_STORAGE permission has not been granted on install, even though it is definitely in the manifest (I've used apktool to check it wasn't stripped out somehow). – TheBestBigAl Jan 09 '17 at 17:04
  • I've just noticed something interesting. When I side load the app and it lists permissions that are needed, I don't see "modify or delete the contents of your SD card" and "read the contents of your SD card", which I do see when I install another app. This seems very strange since the permissions are clearly in the manifest, would something else be needed to make those permissions appear on install? – TheBestBigAl Jan 09 '17 at 17:08
0

try this:

 String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/MyFolder");    
myDir.mkdirs();
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String fname = "Image-" + n + ".jpg";

File file = new File (myDir, fname);
if (file.exists ()) file.delete (); 
file.createNewFile();
try {
       FileOutputStream out = new FileOutputStream(file);
       FileInputStream in = new FileInputStream(filePath);
        byte[] buf = new byte[1024];
        int len;

        while ((len = in.read(buf)) > 0) {
            out.write(buf, 0, len);
        }

        in.close();
        out.flush();
        out.close();

} catch (Exception e) {
       e.printStackTrace();
}

also add both read and write permission to the manifest

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
rafsanahmad007
  • 23,683
  • 6
  • 47
  • 62