Skip to content

Instantly share code, notes, and snippets.

@PauloLuan
Last active October 31, 2022 07:02
Show Gist options
  • Save PauloLuan/4bcecc086095bce28e22 to your computer and use it in GitHub Desktop.
Save PauloLuan/4bcecc086095bce28e22 to your computer and use it in GitHub Desktop.
how to get the external sd card path on android.
public static String getExternalSdCardPath() {
String path = null;
File sdCardFile = null;
List<String> sdCardPossiblePath = Arrays.asList("external_sd", "ext_sd", "external", "extSdCard");
for (String sdPath : sdCardPossiblePath) {
File file = new File("/mnt/", sdPath);
if (file.isDirectory() && file.canWrite()) {
path = file.getAbsolutePath();
String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmmss").format(new Date());
File testWritable = new File(path, "test_" + timeStamp);
if (testWritable.mkdirs()) {
testWritable.delete();
}
else {
path = null;
}
}
}
if (path != null) {
sdCardFile = new File(path);
}
else {
sdCardFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath());
}
return sdCardFile.getAbsolutePath();
}
@PauloLuan
Copy link
Author

Added write verification.

@cundong
Copy link

cundong commented Jul 7, 2014

Maybe we should do some modification:

from:
List sdCardPossiblePath = Arrays.asList("external_sd", "ext_sd", "external", "extSdCard");

to:
List sdCardPossiblePath = Arrays.asList("external_sd", "ext_sd", "external", "extSdCard", "sdcard2");

@anujdeo
Copy link

anujdeo commented Sep 10, 2014

I am looking for the solution to get External SD Card path, But couldn't find perfect one. Your solution seems better than those out there, but I think it is not full-proof as Different Manufacturers uses different Paths. And this way it is impossible to hard-code and scan through all possible paths.

Here are some possible External Storage paths: (Sorry couldn't find original source ):

/storage/sdcard1 //!< Motorola Xoom
/storage/extsdcard //!< Samsung SGS3
/storage/sdcard0/external_sdcard // user request
/mnt/extsdcard
/mnt/sdcard/external_sd //!< Samsung galaxy family
/mnt/external_sd
/mnt/media_rw/sdcard1 //!< 4.4.2 on CyanogenMod S3
/removable/microsd //!< Asus transformer prime
/mnt/emmc
/storage/external_SD //!< LG
/storage/ext_sd //!< HTC One Max
/storage/removable/sdcard1 //!< Sony Xperia Z1
/data/sdext
/data/sdext2
/data/sdext3
/data/sdext4

Hope it helps you. :)

@pareshdevatval
Copy link

thank you anujdeo...

@rohitvairagkar
Copy link

is there any option other than hard coding of external sd card names?????

@paresh996
Copy link

I just figured out something. At least for every phone I came across today and even my Android Emulator had the SD Card Path like ' /storage/????-???? ' where every ? is a capital letter or a digit.

So, if /storage/ directory has a directory which is readable and that is not the internal storage directory, it must be the SD Card.

My code worked on all phones I tested and even on my android emulator!

    String removableStoragePath;
        File fileList[] = new File("/storage/").listFiles();
        for (File file : fileList)
      {     if(!file.getAbsolutePath().equalsIgnoreCase(Environment.getExternalStorageDirectory().getAbsolutePath()) && file.isDirectory() && file.canRead())
        	removableStoragePath = file.getAbsolutePath();  }
        //If there is an SD Card, removableStoragePath will have it's path. If there isn't it will be an empty string.

If there is an SD Card, removableStoragePath will have it's path. If there isn't it will be an empty string.

@sqro2
Copy link

sqro2 commented Apr 24, 2017

paresh996 you are absolutely correct. I have tested your code on my device(Gionee) and it worked . But i heard that samsung manufacturer put the removable storage in mnt/extSdCard/ .Did you tested this on samsung as well?

@Tichex03
Copy link

Greate code PauloLuan ! Really saved Me , Looking for this from 10 days of searching everysite.....

@lovelyelfpop
Copy link

lovelyelfpop commented May 16, 2018

/**
 * Get external sd card path using reflection
 * @param mContext
 * @param is_removable is external storage removable
 * @return
 */
private static String getExternalStoragePath(Context mContext, boolean is_removable) {

    StorageManager mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
    Class<?> storageVolumeClazz = null;
    try {
        storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");
        Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");
        Method getPath = storageVolumeClazz.getMethod("getPath");
        Method isRemovable = storageVolumeClazz.getMethod("isRemovable");
        Object result = getVolumeList.invoke(mStorageManager);
        final int length = Array.getLength(result);
        for (int i = 0; i < length; i++) {
            Object storageVolumeElement = Array.get(result, i);
            String path = (String) getPath.invoke(storageVolumeElement);
            boolean removable = (Boolean) isRemovable.invoke(storageVolumeElement);
            if (is_removable == removable) {
                return path;
            }
        }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
    return null;
}

@miszmaniac
Copy link

Kotlin version:

private fun getExternalCardDirectory(): File? {
        val storageManager = getSystemService(Context.STORAGE_SERVICE)
        try {
            val storageVolumeClazz = Class.forName("android.os.storage.StorageVolume")
            val getVolumeList = storageManager.javaClass.getMethod("getVolumeList")
            val getPath = storageVolumeClazz.getMethod("getPath")
            val isRemovable = storageVolumeClazz.getMethod("isRemovable")
            val result = getVolumeList.invoke(storageManager) as Array<StorageVolume>
            result.forEach {
                if (isRemovable.invoke(it) as Boolean) {
                    return File(getPath.invoke(it) as String)
                }
            }
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return null
    }

@feelgoodincorp
Copy link

lovelyelfpop's version works great, thank you!

@djkskqyr3
Copy link

@lovelyelfpop Great, it works

@zgrujic
Copy link

zgrujic commented Sep 26, 2019

@lovelyelfpop God bless you, seems this is the only working solution on internet currently. Thanks a bunch!!

@bhanubais
Copy link

In Samsung external card location has changed as:
/storage/0000-0000/

@JoeCodeswell
Copy link

Thanks, @lovelyelfpop this worked on my Samsung SM-T320 running Android version 4.4.2.

  1. I followed get Context in non-Activity class [duplicate] to get the context into my Util class from the MainActivity.
  2. Here's some things I imported. there might have been a couple more.
import android.os.storage.StorageManager;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

Thanks again. This worked like a champ

Copy link

ghost commented Nov 10, 2020

@lovelyelfpop Thank you, very much

@Alkwin
Copy link

Alkwin commented Feb 14, 2022

Hi,

After Android Q, the method getPath cannot be called through reflection.

For me, the following code works. Tested on around 6-7 devices, ranging from Android 4.3 up to Android 12.

private fun getExternalCardDirectory(): String {
        val storageManager = context.getSystemService(Context.STORAGE_SERVICE)
        try {
            val storageVolumeClassReflection = Class.forName("android.os.storage.StorageVolume")
            val getVolumeList = storageManager.javaClass.getMethod("getVolumeList")
            val getPath = if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                storageVolumeClassReflection.getMethod("getDirectory")
            } else {
                storageVolumeClassReflection.getMethod("getPath")
            }
            val isRemovable = storageVolumeClassReflection.getMethod("isRemovable")
            val result = getVolumeList.invoke(storageManager) as Array<StorageVolume>
            result.forEach {
                if (isRemovable.invoke(it) as Boolean) {
                    return when(val invokeResult = getPath.invoke(it)) {
                        is File -> invokeResult.absolutePath

                        is String -> invokeResult

                        else -> DEFAULT_VALUE.also {
                            log.debug { "Reflection unsupported type; Invoke result: $invokeResult" }
                        }
                    }
                }
            }
        } catch (e: Throwable) {
            log.debug { "Could not get SD card path; Exception: $e" }
        }
        return DEFAULT_VALUE
    }

With DEFAULT_VALUE = "N/A"
Credit @lovelyelfpop

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment