PS:看了9年的小说,自己开始动手写了一本,请各位猿们动动手指,点击下,有起点账号的可以收藏下!!《武意长存》

忘了这篇文章是在哪里看到了,当时就copy保存了下来,今天转载出来下。

外置sd卡路径,也许很多同学在平时的工作中并不会用到,因为现在很多机型都不支持外置sd卡(这也是Google目标),所以并不用考虑外置sd卡的路径问题。除了开发文件管理类的应用之外,其他应用使用 Enviroment 这个类中的一些静态方法就能满足需要。但也有一些特殊需求需要用到外置sd卡路径,那怎么才能准确获得外置sd卡的路径呢?

方法一

//内置sd卡路径
String sdcardPath = System.getenv("EXTERNAL_STORAGE");
//内置sd卡路径
String sdcardPath = Environment.getExternalStorageDirectory().getAbsolutePath();
//外置置sd卡路径
String extSdcardPath = System.getenv("SECONDARY_STORAGE");

在Enviroment类的源码中获得sd卡路径其实也是通过 System.getnv() 方法来实现的,如隐藏的方法:

/** {@hide} */
public static File getLegacyExternalStorageDirectory() {return new File(System.getenv(ENV_EXTERNAL_STORAGE));
}

注:更详细的内容还是去看Enviroment源码。

另外要注意的是,在API 23版本中 SECONDARY_STORAGE 被移除。

方法二

private static String getStoragePath(Context mContext, boolean is_removale) {  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_removale == 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;
}

通过反射的方式使用在sdk中被 隐藏 的类 StroageVolume 中的方法getVolumeList(),获取所有的存储空间(Stroage Volume),然后通过参数is_removable控制,来获取内部存储和外部存储(内外sd卡)的路径,参数 is_removable为false时得到的是内置sd卡路径,为true则为外置sd卡路径。

在API 23 Enviroment 类中的内部类 UserEnvironment 中有一方法getExternalDirs与此一样,代码如下:

public File[] getExternalDirs() {final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId,StorageManager.FLAG_FOR_WRITE);final File[] files = new File[volumes.length];for (int i = 0; i < volumes.length; i++) {files[i] = volumes[i].getPathFile();}return files;
}

再看Enviroment的getExternalStorageDirectory方法实现:

public static File getExternalStorageDirectory() {throwIfUserRequired();return sCurrentUser.getExternalDirs()[0];
}

可以看出,在API 23时,先是通过getExternalDirs()获取到所有存储空间的File[]数组,这个数组的第一个值:getExternalDirs()[0],即为内置sd卡所在路径。

而在API 23 之前的版本中,并没有类似getExternalDirs()的方法通过StorageVolume直接获得存储空间(Storage Volume),而时通过别的方式来实现的,看关键方法的源码:

public static File getExternalStorageDirectory() {throwIfUserRequired();return sCurrentUser.getExternalDirsForApp()[0];
}

这里的 getExternalDirsForApp() 和上面的 getExternalDirs() 的作用是一样的,都是得到所有存储空间的File[]数组。

public File[] getExternalDirsForApp() {return mExternalDirsForApp;
}

mExternalDirsForApp 是在 Enviroment 类中的内部类 UserEnvironment 的构造方法中初始化的,Enviroment#UserEnvironment构造函数源码如下:

        public UserEnvironment(int userId) {// See storage config details at http://source.android.com/tech/storage/String rawExternalStorage = System.getenv(ENV_EXTERNAL_STORAGE);String rawEmulatedSource = System.getenv(ENV_EMULATED_STORAGE_SOURCE);String rawEmulatedTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET);String rawMediaStorage = System.getenv(ENV_MEDIA_STORAGE);if (TextUtils.isEmpty(rawMediaStorage)) {rawMediaStorage = "/data/media";}ArrayList<File> externalForVold = Lists.newArrayList();ArrayList<File> externalForApp = Lists.newArrayList();if (!TextUtils.isEmpty(rawEmulatedTarget)) {// Device has emulated storage; external storage paths should have// userId burned into them.final String rawUserId = Integer.toString(userId);final File emulatedSourceBase = new File(rawEmulatedSource);final File emulatedTargetBase = new File(rawEmulatedTarget);final File mediaBase = new File(rawMediaStorage);// /storage/emulated/0externalForVold.add(buildPath(emulatedSourceBase, rawUserId));externalForApp.add(buildPath(emulatedTargetBase, rawUserId));// /data/media/0mEmulatedDirForDirect = buildPath(mediaBase, rawUserId);} else {// Device has physical external storage; use plain paths.if (TextUtils.isEmpty(rawExternalStorage)) {Log.w(TAG, "EXTERNAL_STORAGE undefined; falling back to default");rawExternalStorage = "/storage/sdcard0";}// /storage/sdcard0externalForVold.add(new File(rawExternalStorage));externalForApp.add(new File(rawExternalStorage));// /data/mediamEmulatedDirForDirect = new File(rawMediaStorage);}// Splice in any secondary storage paths, but only for ownerfinal String rawSecondaryStorage = System.getenv(ENV_SECONDARY_STORAGE);if (!TextUtils.isEmpty(rawSecondaryStorage) && userId == UserHandle.USER_OWNER) {for (String secondaryPath : rawSecondaryStorage.split(":")) {externalForVold.add(new File(secondaryPath));externalForApp.add(new File(secondaryPath));}}mExternalDirsForVold = externalForVold.toArray(new File[externalForVold.size()]);mExternalDirsForApp = externalForApp.toArray(new File[externalForApp.size()]);}

也可以根据这个方法得到一个获取所有存储空间的路径的方法getStorageDirectories():

/**
     * Returns all available SD-Cards in the system (include emulated)
     * <p/>
     * Warning: Hack! Based on Android source code of version 4.3 (API 18)
     * Because there is no standard way to get it.
     * TODO: Test on future Android versions 4.4+
     *
     * @return paths to all available SD-Cards in the system (include emulated)
     */private static final Pattern DIR_SEPARATOR = Pattern.compile("/");public List<String> getStorageDirectories() {// Final set of pathsfinal ArrayList<String> rv = new ArrayList<String>();// Primary physical SD-CARD (not emulated)final String rawExternalStorage = System.getenv("EXTERNAL_STORAGE");// All Secondary SD-CARDs (all exclude primary) separated by ":"final String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE");// Primary emulated SD-CARDfinal String rawEmulatedStorageTarget = System.getenv("EMULATED_STORAGE_TARGET");if (TextUtils.isEmpty(rawEmulatedStorageTarget)) {// Device has physical external storage; use plain paths.if (TextUtils.isEmpty(rawExternalStorage)) {// EXTERNAL_STORAGE undefined; falling back to default.rv.add("/storage/sdcard0");} else {rv.add(rawExternalStorage);}} else {// Device has emulated storage; external storage paths should have// userId burned into them.final String rawUserId;if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {rawUserId = "";} else {final String path = Environment.getExternalStorageDirectory().getAbsolutePath();final String[] folders = DIR_SEPARATOR.split(path);final String lastFolder = folders[folders.length - 1];boolean isDigit = false;try {Integer.valueOf(lastFolder);isDigit = true;} catch (NumberFormatException ignored) {}rawUserId = isDigit ? lastFolder : "";}// /storage/emulated/0[1,2,...]if (TextUtils.isEmpty(rawUserId)) {rv.add(rawEmulatedStorageTarget);} else {rv.add(rawEmulatedStorageTarget + File.separator + rawUserId);}}// Add all secondary storagesif (!TextUtils.isEmpty(rawSecondaryStoragesStr)) {// All Secondary SD-CARDs splited into arrayfinal String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator);Collections.addAll(rv, rawSecondaryStorages);}rootmode = Sp.getBoolean("rootmode", false);if (rootmode)rv.add("/");File usb = getUsbDrive();if (usb != null && !rv.contains(usb.getPath())) rv.add(usb.getPath());return rv;}
public File getUsbDrive() {File parent;parent = new File("/storage");try {for (File f : parent.listFiles()) {if (f.exists() && f.getName().toLowerCase().contains("usb") && f.canExecute()) {return f;}}} catch (Exception e) {}parent = new File("/mnt/sdcard/usbStorage");if (parent.exists() && parent.canExecute())return (parent);parent = new File("/mnt/sdcard/usb_storage");if (parent.exists() && parent.canExecute())return parent;return null;}

综上分析,通过方法一和方法二都可以正确的获取内外sd卡路径,但方法一会存在以下问题:

1、API>=23 时方法一无效(暂未测试)

2、有些厂商的Rom改动太多,对相关原生API的支持存在问题,这时方法一可能会存在问题。

3、其他一些情况造成的原因(基本与2差不多,是ROM等因素造成的)

所以,在使用时建议使用方法二来获取内外置sd卡路径,在API 23(Android 6.0)之前使用getStorageDirectories() 应该也是OK的。

如何正确获得Android内外SD卡路径相关推荐

  1. Android 获取内外SD卡路径几种方法总结

    今天做项目的时候发现获取存储的方式不一样,搞了一个上午,计算sd卡的容量.总结一下.以免后面走弯路 Android 获取SD卡路径: 外置sd卡路径,也许很多同学在平时的工作中并不会用到,因为现在很多 ...

  2. Android 获取SD卡路径和判断SD卡是否存在.

    android获取sd卡路径方法: public String getSDPath(){ File sdDir = null; boolean sdCardExist =Environment.get ...

  3. android 华为sd卡路径,(科普)详解Android系统SD卡各类文件夹名称

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 系统数据类--系统文件存储相关文件夹 1..android_secure:官方app2sd的产物,存储了相关的软件使用认证验证,删除之后SD卡中的软件将无 ...

  4. Android 通过sd卡路径获取指定文件夹的所有数据

    File file=new File("/sdcard/Music");File[] files=file.listFiles();if (files == null){Log.e ...

  5. android sd卡无法挂载,内外SD卡无法挂载的BUG修复方法

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 我们在对安卓ROM进行移植的时候,因为移植相对来说比较麻烦,经常会出现很多的问题,特别是常出现的一个问题,就是ROM移植之后无法挂载内外SD卡.接下来就来 ...

  6. android 获取sd卡目录失败_Android获取外置SD卡存储路径的方法

    在开发应用的过程中,经常会遇到需要获取设备存储路径的问题.而从网上看到的很多方法获取到的都是内置存储位置,并非外置SD卡路径,因此我推荐使用反射的机制来获取外置存储的路径. 通常,使用Environm ...

  7. android 获取sd卡目录失败_解决Android手机自带内部存储路径存在但是却获取不到内容的问题...

    我有一台中兴的Android手机,型号是 ZTE U930HD,手机没有插入外置SD卡(也就是Micro SD Card,原名Trans-flash Card(TF卡),2004年正式更名为Micro ...

  8. android 手机获取外置SD卡路径

    一部分手机将eMMC存储挂载到 /mnt/external_sd ./mnt/sdcard2 等节点,而将外置的SD卡挂载到 Environment.getExternalStorageDirecto ...

  9. android storage 路径,Android得到的真机的SD卡路径是 /storage/emulated/0/!!!!

    如题,一个小时前测试得到还是正确路径,现在得到的却是/storage/emulated/0/,NEXUS4和GALAXY S2都得不到正确的,有一台中兴能得到正确的.权限什么的都加好了. 之前还可以的 ...

最新文章

  1. KTable的简单介绍
  2. apache mysql 连接数_浏览器端同时请求100个url后,如何提升有效的msyql连接数
  3. Spring Cloud 使用 FeignClient 启动报错
  4. 牛客竞赛语法入门班数组模拟、枚举、贪心习题【未完结】
  5. 苹果系统的自带的系统录屏软件中新录制的视频会出现在这里!
  6. HDU 6631 line symmetric(枚举)
  7. vuex最简单、最详细的入门文档
  8. 编写一个生成器需要编写__iter__和__next__
  9. python 进制间相互转换
  10. 再见2018,你好2019
  11. Android中实现Activity的透明背景效果
  12. 今日头条品质优化 - 图文详情页秒开实践
  13. 管理感情:精力有限,要么干活,要么内斗
  14. Acronis Disk Director 增大c盘
  15. 计算机原理电梯控制系统设计,基于PLC的电梯控制系统的设计与研究
  16. 使用JavaScript创建模块化的双人对战象棋程序
  17. android 使用adb命令安装安卓apk包
  18. 科研必备 | 谷歌学术高级搜索详解
  19. C300 之SFU设备配置指导
  20. Python爬取招聘网站

热门文章

  1. 总结之:CentOS 6.5 MySQL/MariaDB日志及事物详解和基本操作语句
  2. MONKOVEL-安卓端免费的小说阅读器 源码分享
  3. 高等数学拾遗 矢量分析
  4. 高德地图api的使用
  5. 微信后台基于时间序的海量数据冷热分级架构设计实践
  6. 如何制作一款灵活的工单管理系统【推荐】
  7. Redis基本数据类型、持久化机制、集群模式、淘汰策略、缓存穿透、击穿、雪崩、常见面试题大集合!
  8. 深入理解浏览器兼容性模式
  9. 快速制作一个chrome插件
  10. egret内存泄漏整理学习