8

While writing file in External SD card I am getting an error EACCESS permission denied. I have set the permission <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> But the when I read the file I am successfully able to read it but not able to write the file. The code that I am using for writing the file in SD card is:

String path="mnt/extsd/Test";

                try{
                    File myFile = new File(path, "Hello.txt");              //device.txt
                    myFile.createNewFile();
                    FileOutputStream fOut = new FileOutputStream(myFile);

                    OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
                    myOutWriter.append(txtData.getText());
                    myOutWriter.close();
                    fOut.close();
                    Toast.makeText(getBaseContext(),"Done writing SD "+myFile.getPath(),Toast.LENGTH_SHORT).show();
                } catch (Exception e) {
                    Toast.makeText(getBaseContext(), e.getMessage(),Toast.LENGTH_SHORT).show();
                    System.out.println("Hello"+e.getMessage());
                }
            }

The path for the external storage card is mnt/extsd/. Thats why I am not able to use Environment.getExternalStorageDirectory().getAbsolutePath() which is giving me a path mnt/sdcard and this path is for internal storage path in my tablet. Please suggest why this is so n how can I resolve this

CodingDecoding
  • 433
  • 2
  • 9
  • 20

4 Answers4

17

As I remember Android got a partial multi-storage support since Honeycomb, and the primary storage (the one you get from Environment.getExternalStorageDirectory, usually part of the internal eMMC card) is still protected by the permission WRITE_EXTERNAL_STORAGE, but the secondary storages (like the real removable SD card) are protected by a new permission android.permission.WRITE_MEDIA_STORAGE, and the protection level is signatureOrSystem, see also the discussion in this article.

If this is the case then it seems impossible for an normal app to write anything to the real sdcard without a platform signature...

Karthik
  • 3,509
  • 1
  • 20
  • 26
Ziteng Chen
  • 1,959
  • 13
  • 13
  • Do you have root access to your tablet? If yet then you may do a test like this: 1) let your app use the WRITE_MEDIA_STORAGE permission and then rebuild it; 2) uninstall your app if it is already installed, then run "adb root", "adb remount", "adb push YouApp.apk /system/app/YouApp.apk" this will make your app a system app; 3) start your app and check if the test code is working or not. If yes there seems no other way around except signing the app by platform certificate or making it a system app. Or you can wait to see if anyone else have a better idea. – Ziteng Chen Oct 12 '12 at 10:48
  • 1
    This permission is enforced starting in API level 19. Before API level 19, this permission is not enforced and all apps still have access to read from external storage. You can test your app with the permission enforced by enabling Protect USB storage under Developer options in the Settings app on a device running Android 4.1 or higher. -- http://developer.android.com/reference/android/Manifest.permission.html -- seems like it is already enforced behind the scene? – hB0 Nov 06 '13 at 16:22
  • android.permission.WRITE_MEDIA_STORAGE this permission is only granted to system apps – Michelle Mar 12 '15 at 06:04
  • 1
    In my case on Lenovo A7-20 on android 4.4.2, Es file explorer doesn't have any issue in read/write of the files only my application has issue writing to memory card, i wonder how! – Anup Aug 08 '16 at 09:07
7

From API level 19, Google has added API.

  • Context.getExternalFilesDirs()
  • Context.getExternalCacheDirs()
  • Context.getObbDirs()

Apps must not be allowed to write to secondary external storage devices, except in their package-specific directories as allowed by synthesized permissions. Restricting writes in this way ensures the system can clean up files when applications are uninstalled.

Following is approach to get application specific directory on external SD card with absolute paths.

Context _context = this.getApplicationContext();

File fileList2[] = _context.getExternalFilesDirs(Environment.DIRECTORY_DOWNLOADS);

if(fileList2.length == 1) {
    Log.d(TAG, "external device is not mounted.");
    return;
} else {
    Log.d(TAG, "external device is mounted.");
    File extFile = fileList2[1];
    String absPath = extFile.getAbsolutePath(); 
    Log.d(TAG, "external device download : "+absPath);
    appPath = absPath.split("Download")[0];
    Log.d(TAG, "external device app path: "+appPath);

    File file = new File(appPath, "DemoFile.png");

    try {
        // Very simple code to copy a picture from the application's
        // resource into the external file.  Note that this code does
        // no error checking, and assumes the picture is small (does not
        // try to copy it in chunks).  Note that if external storage is
        // not currently mounted this will silently fail.
        InputStream is = getResources().openRawResource(R.drawable.ic_launcher);
        Log.d(TAG, "file bytes : "+is.available());

        OutputStream os = new FileOutputStream(file);
        byte[] data = new byte[is.available()];
        is.read(data);
        os.write(data);
        is.close();
        os.close();
    } catch (IOException e) {
        // Unable to create file, likely because external storage is
        // not currently mounted.
        Log.d("ExternalStorage", "Error writing " + file, e);
    }
}

Log output from above looks like:

context.getExternalFilesDirs() : /storage/extSdCard/Android/data/com.example.remote.services/files/Download

external device is mounted.

external device download : /storage/extSdCard/Android/data/com.example.remote.services/files/Download

external device app path: /storage/extSdCard/Android/data/com.example.remote.services/files/
Kevin Panko
  • 8,356
  • 19
  • 50
  • 61
Sachin
  • 501
  • 10
  • 18
0

I solved this problem by removing the android:maxSdkVersion="18" in uses-permission in manifest file. I.e. use this:

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

instead of:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
                 android:maxSdkVersion="18" />
EWit
  • 1,954
  • 13
  • 22
  • 19
0

Check if user is having external storage permission or not. If not then use cache dir for saving the file.

final boolean extStoragePermission = ContextCompat.checkSelfPermission(
               context, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                == PackageManager.PERMISSION_GRANTED;

            if (extStoragePermission &&
        Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) {
                parentFile = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
            }
            else{
                parentFile = new File(context.getCacheDir(),    Environment.DIRECTORY_PICTURES);
            }