19

I have been using "Environment.getExternalStorage()" to store and manage files. And there is no warning message from logcat with that method and works greatly fine.

But, My project needs to use method "Context.getExternalFilesDir(String type)" and there is a warning message

ContextImpl:Failed to ensure directory: /storage/external_SD/Android/data/(package name)/files

Fortunately that File object works fine(reading or write or making folder works, too).

But I want to know how to resolve that warning message. Do I miss something?

Abhinav Singh Maurya
  • 3,313
  • 8
  • 33
  • 51
iroiroys
  • 788
  • 1
  • 10
  • 17
  • 1
    @IntelliJAmiya Thanks for quick reply and edit my answer. I checked it and I found rebooting is a solution, so I reboot my test device, however, it still show same warning message. Is it OK ignoring it? – iroiroys Oct 27 '15 at 08:21

3 Answers3

12

You should know how the warning message comes up.

The getExternalFilesDir(String type) will call getExternalFilesDirs(String type) (notice the 's' at the final of the second method name).

The getExternalFilesDirs(String type) will find all dirs of the type, and calls ensureDirsExistOrFilter() at the end to ensure the directories exist.

If the dir can't be reached, it will print a warning!

Log.w(TAG, "Failed to ensure directory: " + dir);
dir = null;

So, if your device has two sdcard paths, it will produce two dirs. If one is not available, the warning will come up.

The conclusion is the warning does not need to be fixed.

Fer
  • 1,956
  • 2
  • 28
  • 35
Hongji Song
  • 121
  • 1
  • 4
  • 1
    You said `If the dir can't be reached, it will print a warning!`, but the messages shows even if the directories are found. like OP said in the question. – ClassA Oct 30 '17 at 13:18
1

If you have code that is iterating files, calling this API many times, this warning can cause log pollution. To solve this (since the warning is actually benign) you can create a wrapper class that stores the result of calling getExternalFilesDir / getExternalCacheDir and subsequently returns the stored value instead of calling the API. In this way, at least you will only ever see this message once.

Mr. Bungle
  • 1,696
  • 17
  • 21
0

I follow the getExternalFilesDir() source

/**
 * Ensure that given directories exist, trying to create them if missing. If
 * unable to create, they are filtered by replacing with {@code null}.
 */
private File[] ensureExternalDirsExistOrFilter(File[] dirs) {
    File[] result = new File[dirs.length];
    for (int i = 0; i < dirs.length; i++) {
        File dir = dirs[i];
        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                // recheck existence in case of cross-process race
                if (!dir.exists()) {
                    // Failing to mkdir() may be okay, since we might not have
                    // enough permissions; ask vold to create on our behalf.
                    final IMountService mount = IMountService.Stub.asInterface(
                            ServiceManager.getService("mount"));
                    try {
                        final int res = mount.mkdirs(getPackageName(), dir.getAbsolutePath());
                        if (res != 0) {
                            Log.w(TAG, "Failed to ensure " + dir + ": " + res);
                            dir = null;
                        }
                    } catch (Exception e) {
                        Log.w(TAG, "Failed to ensure " + dir + ": " + e);
                        dir = null;
                    }
                }
            }
        }
        result[i] = dir;
    }
    return result;
}


immediate use Environment.getExternalStorageDirectory() get ExternalDirs

public final class StorageUtil {

public static final String DIR_ANDROID = "Android";
private static final String DIR_DATA = "data";
private static final String DIR_FILES = "files";
private static final String DIR_CACHE = "cache";

@Nullable
public static synchronized File getExternalStorageAppFilesFile(Context context, String fileName) {
    if (context == null) return null;
    if (fileName == null) return null;
    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
        File dirs = buildExternalStorageAppFilesDirs(Environment.getExternalStorageDirectory().getAbsolutePath(), context.getPackageName());
        return new File(dirs, fileName);
    }
    return null;
}


public synchronized static File buildExternalStorageAppFilesDirs(String externalStoragePath, String packageName) {
    return buildPath(externalStoragePath, DIR_ANDROID, DIR_DATA, packageName, DIR_FILES);
}


public synchronized static File buildPath(String base, String... segments) {
    File cur = new File(base);
    for (String segment : segments) {
        cur = new File(cur, segment);
    }
    return cur;
}

}

任非凡
  • 61
  • 2