14

My development phone is a Nexus 5, running Android 4.4.2.

In my application, I am attempting to create a folder on external storage that will store debug information for my application. Basically it will contain all the commands executed by the application, so that when a user encounters a problem, I have the option of having them send me the information from the debug folder to analyse.

I started off by trying to write a file to the folder, but found there was an error creating the folder. At first I was using mkdir(), then I moved onto mkdirs() which also didn't work.

I have <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> in my manifest.

Here is the code for creating the folder:

    File folder = new File(Environment.getExternalStorageDirectory() + "/DebugData");

    String path = folder.getPath();

    if(!folder.mkdirs() || !folder.exists()){        
            Log.e(LOG_TAG, path + " failed");
        } else {
            Log.d(LOG_TAG, path + " succeeded");
        } 

Here is what I have also tried:

    //Check SD card state
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state) || !Environment.MEDIA_MOUNTED.equals(state)) {
        Log.e(LOG_TAG, "Error: external storage is read only or unavailable");
    } else {
        Log.d(LOG_TAG, "External storage is not read only or unavailable");
    }

This returns that the external storage is not read only or unavailable.

I have also tried different paths, such as File folder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Folder1");

This is where it became really confusing.

I tried development on different phones. Firstly, I grabbed a Galaxy S4 GT-i9505 running Android 4.2.2 and it worked. I was able to create the folders and write to them. This showed me that the code was working. Also the path returned by running the code on the S4 and Nexus 5 was the same.

Then I thought it may be android version specific. So I grabbed a Nexus 4 with Android 4.4.2 and the code worked on it as well. Created the folders and allowed me to write to them.

None of the phones are rooted and are all stock standard. There's no special applications or anything I can think of settings wise on the Nexus 5 that would cause permissions problems. The connection is set to Media Device (MTP).

EDIT:

I should add that I have tried the follow which also did not work:

  • Writing a file to the root directory of the external storage
  • Creating the file in the external storage root directory and writing to it
  • Creating a folder in a path outlined and writing a file to it
  • Creating the file in the path outlined and writing to it

I am confused as to what is causing this, is there anything else I can test or change to fix the issue?

EDIT 2:

Turns out the issue was due to, I think, indexing.

Basically all of the other devices I tested on, allowed me to reconnect the USB connection and view the created files and folders.

For some reason my Nexus 5 doesn't index the folders/files, even though they exist.

I downloaded a different 3rd party file explorer application and noticed all the folders and files were there.

So to view these folders and files via USB debugging, I have to restart the phone in order to re-index them, which seems quite annoying but it is better than it not working at all.

Thanks.

benallansmith
  • 816
  • 3
  • 10
  • 26
  • 1
    Don't use concatenation to create `File` objects. Use the proper `File` constructor, such as `new File(Environment.getExternalStorageDirectory(), "SmartspeedPTdata")`. That may not be the source of your difficulty, but it may help. – CommonsWare Mar 12 '14 at 23:46
  • You can't access the root directory. I've encountered devices where you can't even access the root of external storage. You definitely need proper permissions in your manifest file, especially if you want to write. – Edward Falk Mar 13 '14 at 01:14

8 Answers8

7

In terms of this being an indexing issue with the Nexus, this worked for me:

MediaScannerConnection.scanFile(this, new String[] { file.toString() }, null,
        new MediaScannerConnection.OnScanCompletedListener() {
            public void onScanCompleted(String path, Uri uri) {
                Log.i("ExternalStorage", "Scanned " + path + ":");
                Log.i("ExternalStorage", "-> uri=" + uri);
            }
});

You should call it straight after creating and saving the file. By using the scanner, I was able to see newly created files and directories simply by replugging the device in.

According to the docs:

MediaScannerConnection provides a way for applications to pass a newly created or downloaded media file to the media scanner service. The media scanner service will read metadata from the file and add the file to the media content provider.

Hope this helps someone else.

Liam George Betsworth
  • 18,373
  • 5
  • 39
  • 42
  • This is the real answer. Thanks @Liam. – Zorfling Jul 07 '14 at 03:35
  • Thanks for the answer, @Liam. I'm a bit confused (I'm new): Does this mean that if you want to garuntee that a file your app creates will be viewable when connecting the device to a PC, then this is the code you need to wrap around your 'create directory' or 'create file' code? – username Dec 31 '15 at 02:11
4

Turns out the issue was due to, I think, indexing.

Basically all of the other devices I tested on, allowed me to reconnect the USB connection and view the created files and folders.

For some reason my Nexus 5 doesn't index the folders/files, even though they exist.

I downloaded a different 3rd party file explorer application and noticed all the folders and files were there.

So to view these folders and files via USB debugging, I have to restart the phone in order to re-index them, which seems quite annoying but it is better than it not working at all.

benallansmith
  • 816
  • 3
  • 10
  • 26
4

For android sdk version 23 and above you should check if the user has granted permission of external storage.

private void createFolder() {
    if (isStoragePermissionGranted()) {
        File folder = new File(Environment.getExternalStorageDirectory()+ File.separator + "DebugData");

        if(!folder.exists()){
            folder.mkdir();
        }
    }

public  boolean isStoragePermissionGranted() {
    if (Build.VERSION.SDK_INT >= 23) {
        if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                == PackageManager.PERMISSION_GRANTED) {
            return true;
        } else {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
            return false;
        }
    }
    else { //permission is automatically granted on sdk<23 upon installation
        return true;
    }
}

The code above worked for me and I hope it will work for you.

Bookan
  • 61
  • 7
  • Links to external resources are encouraged, but please add context around the link so your fellow users will have some idea what it is and why it’s there. Always quote the most relevant part of an important link, in case the target site is unreachable or goes permanently offline. – pableiros Jan 31 '17 at 22:22
  • Exactly what I was looking for. Thanks! – Simon Germain Mar 13 '17 at 16:06
3

Had the same problem. Turned out I was testing on Android 6 and did not check for runtime WRITE_EXTERNAL_STORAGE permission.

stoefln
  • 14,498
  • 18
  • 79
  • 138
2

First, new File() is just create object for file connect.
you want use this file, file is exists or createNewFile().
If you want use this file to create directory, check file is exists, isDirectory() after then mkDir().
Second, check Environment.getExternalStorageDirectory is variable path.
You can use DDMS or ADB for work.
Additionaly, I think you add permission for read external storage for something error.

Young Emil
  • 2,220
  • 2
  • 26
  • 37
Amadas
  • 703
  • 1
  • 5
  • 10
1

If you are running an Android device with api >= 23, you need to request permission from user before you call mkdir() function. My previous answer with example code can be found https://stackoverflow.com/a/38694026/5089713

Community
  • 1
  • 1
Diiiiii
  • 209
  • 3
  • 8
1

For Android 10+ add following into manifest:

<application
    android:requestLegacyExternalStorage="true"
    ...

as asking for Manifest.permission.WRITE_EXTERNAL_STORAGE is no more enough.

Jarda Pavlíček
  • 1,636
  • 17
  • 16
0

Typically, I do this:

/**
 * Return a dedicated directory named "MyApp" at the top of external storage
 */
public static file getDataDir() {
    File sdcard = Environment.getExternalStorageDirectory();
    if( sdcard == null || !sdcard.isDirectory() ) {
        // TODO: warning popup
        Log.w(TAG, "Storage card not found " + sdcard);
        return null;
    }
    File dataDir = new File(sdcard, "MyApp");
    if( !confirmDir(dataDir) ) {
        // TODO: warning popup
        Log.e(TAG, "Unable to create " + dataDir);
        return null;
    }
    return dataDir;
}   

private static boolean confirmDir(File dir) {
    if (dir.isDirectory()) return true;  // already exists
    if (dir.exists()) return false;      // already exists, but is not a directory
    return dir.mkdirs();                 // create it
}       

Also, add this permission to your manifest:

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

If you want private storage (typically under /data/) for your app (not on sdcard), then look into getDir(), getFilesDir(), fileList(), openFileInput(), openFileOutput(), etc.

There are also helper functions to get private directories within the sdcard for API 8 and above: getExternalFilesDir(), getExternalCacheDir(), etc.

Edward Falk
  • 9,991
  • 11
  • 77
  • 112
  • Edward, you did not read exactly description given by benallansmith! He wrote that his VERSION IS 4.4.x!! Did you know about changes in 4.4.x ? Your description said that you are not. – Andrew Niken Jun 17 '15 at 23:06
  • I have to admit that I was unaware of anything new in 4.4. What new APIs are you thinking of? – Edward Falk Jun 19 '15 at 04:11
  • **Environment.getExternalStorageDirectory** doesn't work on modern devices – IgorGanapolsky Mar 02 '18 at 20:26
  • Here's the documentation: https://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory(). It still seems to be a supported API; in what way does it no longer work? – Edward Falk Mar 08 '18 at 22:12