Jono
Jono

Reputation: 18108

Get correct path to External SDCard in android

i am trying to get the correct path to the sd card that is inside my samsung s4 android device through my app but when i try the above paths:

  String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath();
        String pathTwo = Environment.getExternalStorageDirectory().getAbsolutePath();
        String path3 = getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath();

It gets the private none-writable path of /storage/emulated/0 instead of the correct path of storage/sdcard1

I found the correct path via File explorer using the Android Device monitor but i do not want to hard code the path as the path can be different depending on the device.

kind regards

Upvotes: 0

Views: 2147

Answers (4)

user12711116
user12711116

Reputation:

This function will return the path of SD Card path.

private String getExternalSdCard(){
   String finalPath = null;
   File sdCardFile = ContextCompat.getExternalFilesDirs(this, null)[1];
   String base = String.format("/Android/data/%s/files", getPackageName());

   String path = sdCardFile.getAbsolutePath();
   if(path.contains(base)){
       finalPath = path.replace(base, "");
   }
   return finalPath;

}

To get all the list of storage. Use Loop

private String[] storages() {
    List<String> storages = new ArrayList<>();

    try {
        File[] externalStorageFiles = ContextCompat.getExternalFilesDirs(this, null);

        String base = String.format("/Android/data/%s/files", getPackageName());

        for (File file : externalStorageFiles) {
            try {
                if (file != null) {
                    String path = file.getAbsolutePath();

                    if (path.contains(base)) {
                        String finalPath = path.replace(base, "");

                        if (validPath(finalPath)) {
                            storages.add(finalPath);
                        }
                    }
                }
            } catch (Exception e) {
                CrashUtils.report(e);
            }
        }
    } catch (Exception e) {
        CrashUtils.report(e);
    }

    String[] result = new String[storages.size()];
    storages.toArray(result);

    return result;
}

Upvotes: 0

Gautam
Gautam

Reputation: 1345

For all devices

String sSDpath = null;
            File   fileCur = null;
            for( String sPathCur : Arrays.asList( "MicroSD","external_SD","sdcard1","ext_card", "external_sd", "ext_sd", "external", "extSdCard",  "externalSdCard")) // external sdcard
             {

               fileCur = new File( "/mnt/", sPathCur);
               if( fileCur.isDirectory() && fileCur.canWrite())
                 {
                   sSDpath = fileCur.getAbsolutePath();
                   break;
                 }
               if( sSDpath == null)  {
               fileCur = new File( "/storage/", sPathCur);
               if( fileCur.isDirectory() && fileCur.canWrite())
                 {
                   sSDpath = fileCur.getAbsolutePath();
                   break;
                 }
               }
               if( sSDpath == null)  {
               fileCur = new File( "/storage/emulated", sPathCur);
               if( fileCur.isDirectory() && fileCur.canWrite())
                 {
                   sSDpath = fileCur.getAbsolutePath();
Log.e("path",sSpath);
                   break;
                 }
               }
             }

100% working, tested on multiple device.

Upvotes: 4

sudo_rizwan
sudo_rizwan

Reputation: 584

As gilonm mentioned, external (removable) Sd path varies from device to device, but I wrote a method, which iterates through all the different ext paths that the different manufacturers use, and then it finds the exact match.

It returns empty String if path isn't found. If a path is found, you still need to verify whether the card is inserted or not. (By checking if sub-folders exist on that path)

Note: I used StreamSupport library inside the method, so you'll need to download the jar file and add it to libs folder of your project and that's it, it'll work!

   public static String getExternalSdPath(Context context) {
    List<String> listOfFoldersToSearch = Arrays.asList("/storage/", "/mnt/", "/removable/", "/data/");
    final List<String> listOf2DepthFolders = Arrays.asList("sdcard0", "media_rw", "removable");
    final List<String> listOfExtFolders = Arrays.asList("sdcard1", "extsdcard", "external_sd", "microsd", "emmc", "ext_sd", "sdext",
            "sdext1", "sdext2", "sdext3", "sdext4");
    final String[] thePath = {""};
    Optional<File> optional = StreamSupport.stream(listOfFoldersToSearch)
            .filter(new Predicate<String>() {
                @Override
                public boolean test(final String s) {
                    File folder = new File(s);
                    return folder.exists() && folder.isDirectory();
                }
            }) //I got the ones that exist and are directories
            .flatMap(new Function<String, Stream<File>>() {
                @Override
                public Stream<File> apply(final String s) {
                    try {
                        List<File> files = Arrays.asList(new File(s).listFiles());
                        return StreamSupport.stream(files);
                    } catch (NullPointerException e) {
                        return StreamSupport.stream(new ArrayList<File>());
                    }
                }
            }) //I got all sub-dirs of the main folders
            .flatMap(new Function<File, Stream<File>>() {
                @Override
                public Stream<File> apply(final File file1) {
                    if (listOf2DepthFolders.contains(file1.getName()
                            .toLowerCase())) {
                        try {
                            List<File> files = Arrays.asList(file1.listFiles());
                            return StreamSupport.stream(files);
                        } catch (NullPointerException e) {
                            return StreamSupport.stream(Collections.singletonList(file1));
                        }
                    } else
                        return StreamSupport.stream(Collections.singletonList(file1));
                }
            }) //Here I got all the 2 depth and 3 depth folders
            .filter(new Predicate<File>() {
                @Override
                public boolean test(final File o) {
                    return listOfExtFolders.contains(o.getName()
                            .toLowerCase());
                }
            })
            .findFirst();

    optional.ifPresent(new Consumer<File>() {
        @Override
        public void accept(final File file) {
            thePath[0] = file.getAbsolutePath();
        }
    });

    Log.e("Path", thePath[0]);

    try {
        ContextCompat.getExternalFilesDirs(context, null);
    } catch (Exception e) {
        Log.e("PathException", thePath[0]);
    }
    return thePath[0];
}

P.S. I tested and verified it on a few HTC and Samsung devices.

Upvotes: 1

gilonm
gilonm

Reputation: 1859

Based on a previous answer, the path to external SD card actually varies with different device manufactures.

"Environment.getExternalStorageDirectory() refers to whatever the device manufacturer considered to be "external storage". On some devices, this is removable media, like an SD card. On some devices, this is a portion of on-device flash. Here, "external storage" means "the stuff accessible via USB Mass Storage mode when mounted on a host machine", at least for Android 1.x and 2.x. 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."

Based on this answer.

So, There is no absolute way to get this path via code.

Upvotes: 3

Related Questions