4

In android I am able to get my phone's removable external storage by use of:

for (File f : context.getExternalFilesDirs("/")) 
    if (Environment.isExternalStorageRemovable(f))
        Log.println(Log.DEBUG, "#", f.getAbsolutePath());

However, this returns /storage/8E6A-06FF/Android/data/test.application/files which isn't what I want as I simply want the removable's root path /storage/8E6A-06FF/. How can I can get the root path of my phone's removable storage?

Crimson Bloom
  • 287
  • 2
  • 13
  • You have that path already. Just remove the superflous starting with /Android/.. – greenapps Aug 29 '17 at 10:03
  • @greenapps `getExternalStorageDirectory()` return the phones non-removable, primary storage, not the secondary one. As for removing `/Android/`, can you be sure that `/Android/` would be in the path on every android phone? – Crimson Bloom Aug 29 '17 at 10:04
  • Yes. I never saw anything else. – greenapps Aug 29 '17 at 10:05
  • `Paths.get(path_string).getParent()` – Mehran Zamani Aug 29 '17 at 10:09
  • @greenapps Do you know if `/storage` is always there? I can use a while loop until `.getParent()` returns storage in that case. – Crimson Bloom Aug 29 '17 at 10:16
  • "How can I can get the root path of my phone's removable storage?" -- since you have no read or write access to this location, I fail to see what the point is. – CommonsWare Aug 29 '17 at 10:56
  • you want to get the file path with its name and its extension . right? What you tried. Post your full code.How you tried? Post everything. i will tell you further – Noorul Aug 29 '17 at 10:59
  • @CommonsWare I said removable storage, in this case it's `/storage/8E6A-06FF/` which I do have R/W permissions to. – Crimson Bloom Aug 29 '17 at 11:05
  • Not on Android 4.4+. Arbitrary access to removable storage was removed years ago. – CommonsWare Aug 29 '17 at 11:06
  • @Noorul No, that's not what I want, the question should be clear enough to tell you that and `getAbsolutePath()` that is in the code I posted, gives the full path anyway. – Crimson Bloom Aug 29 '17 at 11:07
  • @CommonsWare Why don't you tell that to Android makers then as every phone I've had allows it, I'm talking about micro sd cards that you can insert into your phone, if you can't R/W to them then they're pointless to have. – Crimson Bloom Aug 29 '17 at 11:09
  • "as every phone I've had allows it" -- no, they don't. "I'm talking about micro sd cards that you can insert into your phone" -- yes, I am aware of this. "if you can't R/W to them then they're pointless to have" -- the *user* can, through system apps and apps that use the Storage Access Framework, in addition to the per-app directories like `getExternalFilesDirs()`. – CommonsWare Aug 29 '17 at 11:11
  • @CommonsWare I can literally do `for (File f : context.getExternalFilesDirs(""))` `if (Environment.isExternalStorageRemovable(f))` `new File(f.getAbsolutePath() + "/file.txt").createNewFile();` to write to a removable storage. – Crimson Bloom Aug 29 '17 at 11:15
  • Yes. But that is in your application specific 'files' dir. Try to write in the root. Having said that i do not agree with @CommonsWare that one cannot read. Mostly one can. – greenapps Aug 29 '17 at 11:17
  • Wait so how do I write files to the root then? My file explorer can. – Crimson Bloom Aug 29 '17 at 11:23
  • If your file explorer shipped with the device, it is a system app and has arbitrary read/write access to removable storage. If your file explorer was installed separately, it may have asked you to grant access to removable storage via `ACTION_OPEN_DOCUMENT_TREE` (part of the Storage Access Framework), then used `DocumentFile` from there. – CommonsWare Aug 29 '17 at 11:32
  • @greenapps: Yes, I have seen some arbitrary read access. I haven't figured out what the rules are there, other than it is undocumented. My best guess is that files indexed by the `MediaStore` wind up with global read access, but that is just a guess. It's the sort of behavior that I do not recommend that developers rely upon. – CommonsWare Aug 29 '17 at 11:33
  • My experience is that if it is in getExternalFilesDirs() you have read access. – greenapps Aug 29 '17 at 12:00
  • @Coded Apple see my answer may be this will help you out. – Andy Developer Aug 29 '17 at 12:27

5 Answers5

2

You can try this one it is works perfectly for me.It works like a charm with all Os's version.I didn't found any issue so far with this function.

public static String getSDPath() {
    String filepath = "";
    String[] strPath = {"/storage/sdcard1", "/storage/extsdcard",
            "/storage/sdcard0/external_sdcard", "/mnt/extsdcard",
            "/mnt/sdcard/external_sd", "/mnt/external_sd",
            "/mnt/media_rw/sdcard1", "/removable/microsd", "/mnt/emmc",
            "/storage/external_SD", "/storage/ext_sd",
            "/storage/removable/sdcard1", "/data/sdext", "/data/sdext2",
            "/data/sdext3", "/data/sdext4", "/emmc", "/sdcard/sd",
            "/mnt/sdcard/bpemmctest", "/mnt/sdcard/_ExternalSD",
            "/mnt/sdcard-ext", "/mnt/Removable/MicroSD",
            "/Removable/MicroSD", "/mnt/external1", "/mnt/extSdCard",
            "/mnt/extsd", "/mnt/usb_storage", "/mnt/extSdCard",
            "/mnt/UsbDriveA", "/mnt/UsbDriveB"};

    for (String value : strPath) {
        File f = null;
        f = new File(value);
        if (f.exists() && f.isDirectory()) {
            filepath = value;
            break;
        }
    }
    return filepath;
}
Andy Developer
  • 3,071
  • 1
  • 19
  • 39
  • Is there any update for this code?, or does it still work perfectly? – quetzalfir Jun 24 '18 at 18:46
  • 1
    @quetzalfir no need to update for this. This works fine sir :) You just need to check external permission before fetching the directory and from 7.0 onwards you need to implement xml path and permission too. I hope are aware about it. – Andy Developer Jun 25 '18 at 05:23
1

Try this:

for (File f : context.getExternalFilesDirs("/")) 
    if (Environment.isExternalStorageRemovable(f))
        Log.println(Log.DEBUG, "#", f.getParentFile().getParentFile().getParentFile().getParent());

context.getExternalFilesDirs() will always returns application-specific directory. But the good thing is that application-specific directories are always 4 level deep from the root folder of the storage device. So calling getParentFile() four times on the File f instead of f.getAbsolutePath() will get you the root path of your phone's removable storage.

itstauq
  • 81
  • 6
  • And how can someone write to that storage? This actually still worked but I cannot write to the storage – m33ts4k0z Jun 29 '19 at 22:30
1

Maybe just split it at Android?

I tested it, and it works after I request for permission - WRITE_EXTERNAL_STORAGE.

fun getBaseDir(dir: File): String {
    val absPath = dir.absolutePath
    return if (absPath.contains("/Android")) {
        absPath.split("/Android")[0]
    } else {
        absPath
    }
}
Dev Aggarwal
  • 7,627
  • 3
  • 38
  • 50
0

This will loop through files on sdcard root directory. If you want primary storage, just change [1] to [0]. getExternalFilesDirs returns paths to your app directory on primary and secondary storage. After splitting the second path by "Android", the first string will contain path to your secondary storage root. for example in my case it was "/storage/B242-37B2/". Working with minSdkVersion 19+.

            String sdCardRoot = ContextCompat.getExternalFilesDirs(getApplicationContext(), null)[1].getAbsolutePath().split("Android")[0];

            File f = new File(sdCardRoot);
            File[] files = f.listFiles();

            for (File inFile : files){
                Log.d("Files", inFile.getName());
            }
-1

Try this one if it helps you. For more information refer this link.

public static HashSet<String> getExternalMounts() {
    final HashSet<String> out = new HashSet<String>();
    String reg = "(?i).*vold.*(vfat|ntfs|exfat|fat32|ext3|ext4).*rw.*";
    String s = "";
    try {
        final Process process = new ProcessBuilder().command("mount")
                .redirectErrorStream(true).start();
        process.waitFor();
        final InputStream is = process.getInputStream();
        final byte[] buffer = new byte[1024];
        while (is.read(buffer) != -1) {
            s = s + new String(buffer);
        }
        is.close();
    } catch (final Exception e) {
        e.printStackTrace();
    }

    // parse output
    final String[] lines = s.split("\n");
    for (String line : lines) {
        if (!line.toLowerCase(Locale.US).contains("asec")) {
            if (line.matches(reg)) {
                String[] parts = line.split(" ");
                for (String part : parts) {
                    if (part.startsWith("/"))
                        if (!part.toLowerCase(Locale.US).contains("vold"))
                            out.add(part);
                }
            }
        }
    }
    return out;
}

Here is another approach for the same. Source from here.

Environment.getExternalStorageState() returns path to internal SD mount point like "/mnt/sdcard"

But the question is about external SD. How to get a path like "/mnt/sdcard/external_sd" (it may differ from device to device)?

Android has no concept of "external SD", aside from external storage, as described above.

If a device manufacturer has elected to have external storage be on-board flash and also has an SD card, you will need to contact that manufacturer to determine whether or not you can use the SD card (not guaranteed) and what the rules are for using it, such as what path to use for it.

AndiM
  • 2,196
  • 2
  • 21
  • 38