1

When trying to create a simple .txt or .xml external file (NOT on SD card), my app is throwing a FileNotFoundException. If I let the system pick the path (returns /storage/emulated/legacy) it throws EACCES (permission denied). Same as when I set the path manually to "/android/data" (returns /storage/emulated/0/android/data) or "/download" (returns /storage/emulated/0/Download) - both throw EACCES. If I set path to "/document" it throws ENOENT (no such file or directory).

As see below in my code, I do a check before to make sure that external storage is available and not read-only.

I ran this on 2 devices, running 4.4.2 and 4.4.4 I also added "android.permission.MOUNT_UNMOUNT_FILESYSTEMS" in the manifest as suggested in SO answers to try and force the device to use it's own file system and not the PC's when running app through USB, but it seems to keep giving me a path derived from /emulated/ I try debugging from the device itself using the developer options and thus eliminating the possibility of the app accessing the PC's storage, but the debugger on the device just hangs trying to attach.

Of course I have as well: "android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18"

This is very frustrating as there are some similar questions on SO but with very accepted answers.

public static File getExternalStorageDirectory() {
        Log.i("EXTERNAL STORAGE DIR", EXTERNAL_STORAGE_DIRECTORY.toString());
        return EXTERNAL_STORAGE_DIRECTORY;
    }

    public static final File EXTERNAL_STORAGE_DIRECTORY = getDirectory("EXTERNAL_STORAGE", "android/data");

   public static File getDirectory(String variableName, String defaultPath) {
            String path = System.getenv(variableName);
            return path == null ? new File(defaultPath) : new File(path);
    }

        public boolean isExternalStorageReadOnly() {  
              String extStorageState = Environment.getExternalStorageState();  
              if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)) {  
               return true;  
              }  
              return false;  
             }  

     public boolean isExternalStorageAvailable() {  
              String extStorageState = Environment.getExternalStorageState();  
              if (Environment.MEDIA_MOUNTED.equals(extStorageState)) {  
               return true;  
              }  
              return false;  
             }  

        public void writeToSettingsFile(String name, String value){
//          File myDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "/settings.txt");  
//          File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), fileUrl);
//          File myDir = getDirectory("EXTERNAL_STORAGE", "android/data");
//          File myDir = getExternalStorageDirectory();
//          File myDir = new File("download");
            File myDir = new File(Environment.getExternalStorageDirectory() + "/android/data");
            if(!myDir.exists()){
                myDir.mkdirs();
            }
            try{
             String fname = "settings.txt";
             File file = new File (myDir, fname);
             FileOutputStream fOut = new FileOutputStream(file);
             Toast.makeText(context, "you made it, fOut!!!!", Toast.LENGTH_LONG).show();
             props.setProperty(name, value);     
             props.store(fOut, "Settings Properties");
//           props.storeToXML(fOut, "Settings Properties");                      
             fOut.close();

             } catch (FileNotFoundException e) {
                 e.printStackTrace();
                 Log.e("WTF", "No file found!");

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

            }  
galaxigirl
  • 2,390
  • 2
  • 20
  • 29
  • `returns /storage/emulated/0/android/data`. That is a confusing path. Every device has already `/storage/emulated/0/Android/data` so why do you want to create a directory with A changed to a? Better have a look at getExternalFilesDir if you want to use the Android folder. – greenapps Apr 13 '15 at 09:13
  • props is a reference to java.util.Properties class that I set earlier in the code. It is a simple way to set name/value pairs, and is irrelevant to the problem. I succeeded in writing the properties to an internal file, but I need external file since it must be read/writable from sister applications. – galaxigirl Apr 13 '15 at 10:34

2 Answers2

0

I think the problem is in your this line

android:maxSdkVersion="18" .

Cause You are testing on 4.4.2. And this device has api level 19.

Soham
  • 4,397
  • 11
  • 43
  • 71
  • Thanks for your comment, but I added that line as a 'just in case,' since starting with 4.4 'these permissions are not required if you're reading or writing only files that are private to your app.' IOW writing to external storage is native to 4.4 and onward. I will delete that line though since I will eventually need other sister apps to be able to write to the file. – galaxigirl Apr 13 '15 at 10:21
0

Okay this is the solution :

public void writeToSettingsFile(String name, String value){
//          File myDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "/settings.txt");
//          File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), fileUrl);
//          File myDir = getDirectory("EXTERNAL_STORAGE", "android/data");
//          File myDir = getExternalStorageDirectory();
//          File myDir = new File("download");
        File myDir = new File(this.getExternalFilesDir(null), name);
        if(!myDir.exists()){
            myDir.mkdirs();
        }
        try{
            String fname = "settings.txt";
            File file = new File (myDir, fname);
            FileOutputStream fOut = new FileOutputStream(file);

            fOut.write(value.getBytes());

//           props.storeToXML(fOut, "Settings Properties");
            fOut.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Log.e("WTF", "No file found!");

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

    }

Try this method. The problem was you cant get internal directory like this

File myDir = new File(Environment.getExternalStorageDirectory() + "/android/data"); // You don't have the permission to do this 

if you want to write on internal storage you can get directory like this

File myDir = new File(this.getExternalFilesDir(null), name);

And you can take a look to For more information about saving files

Ibrahim Disouki
  • 2,642
  • 4
  • 21
  • 52
  • getExternalFilesDir() delivers a path to external storage of course. getFilesDir() is for internal storage. Its all in the name. – greenapps Apr 13 '15 at 09:39
  • No if you call `Environment.getExternalStorageDirectory()` that returns external storage but if you call `Context.this.getExternalFilesDir(null)` Context here is your application context that return internal storage not external and it will be `storage/emulated/0/Android/data/your application package/files/file name` – Ibrahim Disouki Apr 13 '15 at 09:44
  • And.. That is external storage. Again: external is in the functionname. /data/data/package is internal storage. – greenapps Apr 13 '15 at 10:08
  • Both external functions you mentioned deliver a path that starts the same like /storage/emulated/0. So it is on the same external storage. – greenapps Apr 13 '15 at 10:14
  • The only different between the Internal and External Storage is if you store some files on External storage and user uninstall your app files Will not be deleted But if you store some files on Internal storage and user uninstall your app files Will be deleted also. That is it – Ibrahim Disouki Apr 13 '15 at 10:17
  • If you really believe that then i have to warn you that files in private external memory (by getExternalFilesDir) will be deleted too. Internal and external are two completely different file systems by the way. – greenapps Apr 13 '15 at 10:23
  • Hi thanks for the comments! Perhaps there is some confusion. I want to write to external storage since I need read/write access across several sister apps. External storage as far as Android is concerned can be the SD card (which I don't want), or can be a partition in the device (non-removable), which is available on every Android device. – galaxigirl Apr 13 '15 at 10:26
  • and FYI getExternalFilesDir() is indeed external, but private, which is not my requirements. – galaxigirl Apr 13 '15 at 10:39
  • Well it is private. But any app has access. App specific is a better description. – greenapps Apr 13 '15 at 11:07
  • I didn't understand your last comment - private vs app specific vs app access. Will getExternalFilesDir() allow me to write from the sister apps as well? Tnx :) – galaxigirl Apr 13 '15 at 11:24
  • Yes. Provided your other apps change the included package name accordingly. Easier would be to create your apps specific directory 'OurAppsDir' on external storage directly. – greenapps Apr 13 '15 at 17:08
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/75144/discussion-between-galaxigirl-and-greenapps). – galaxigirl Apr 13 '15 at 18:56