如何正确获得Android内外SD卡路径
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卡路径相关推荐
- Android 获取内外SD卡路径几种方法总结
今天做项目的时候发现获取存储的方式不一样,搞了一个上午,计算sd卡的容量.总结一下.以免后面走弯路 Android 获取SD卡路径: 外置sd卡路径,也许很多同学在平时的工作中并不会用到,因为现在很多 ...
- Android 获取SD卡路径和判断SD卡是否存在.
android获取sd卡路径方法: public String getSDPath(){ File sdDir = null; boolean sdCardExist =Environment.get ...
- android 华为sd卡路径,(科普)详解Android系统SD卡各类文件夹名称
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 系统数据类--系统文件存储相关文件夹 1..android_secure:官方app2sd的产物,存储了相关的软件使用认证验证,删除之后SD卡中的软件将无 ...
- Android 通过sd卡路径获取指定文件夹的所有数据
File file=new File("/sdcard/Music");File[] files=file.listFiles();if (files == null){Log.e ...
- android sd卡无法挂载,内外SD卡无法挂载的BUG修复方法
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 我们在对安卓ROM进行移植的时候,因为移植相对来说比较麻烦,经常会出现很多的问题,特别是常出现的一个问题,就是ROM移植之后无法挂载内外SD卡.接下来就来 ...
- android 获取sd卡目录失败_Android获取外置SD卡存储路径的方法
在开发应用的过程中,经常会遇到需要获取设备存储路径的问题.而从网上看到的很多方法获取到的都是内置存储位置,并非外置SD卡路径,因此我推荐使用反射的机制来获取外置存储的路径. 通常,使用Environm ...
- android 获取sd卡目录失败_解决Android手机自带内部存储路径存在但是却获取不到内容的问题...
我有一台中兴的Android手机,型号是 ZTE U930HD,手机没有插入外置SD卡(也就是Micro SD Card,原名Trans-flash Card(TF卡),2004年正式更名为Micro ...
- android 手机获取外置SD卡路径
一部分手机将eMMC存储挂载到 /mnt/external_sd ./mnt/sdcard2 等节点,而将外置的SD卡挂载到 Environment.getExternalStorageDirecto ...
- android storage 路径,Android得到的真机的SD卡路径是 /storage/emulated/0/!!!!
如题,一个小时前测试得到还是正确路径,现在得到的却是/storage/emulated/0/,NEXUS4和GALAXY S2都得不到正确的,有一台中兴能得到正确的.权限什么的都加好了. 之前还可以的 ...
最新文章
- KTable的简单介绍
- apache mysql 连接数_浏览器端同时请求100个url后,如何提升有效的msyql连接数
- Spring Cloud 使用 FeignClient 启动报错
- 牛客竞赛语法入门班数组模拟、枚举、贪心习题【未完结】
- 苹果系统的自带的系统录屏软件中新录制的视频会出现在这里!
- HDU 6631 line symmetric(枚举)
- vuex最简单、最详细的入门文档
- 编写一个生成器需要编写__iter__和__next__
- python 进制间相互转换
- 再见2018,你好2019
- Android中实现Activity的透明背景效果
- 今日头条品质优化 - 图文详情页秒开实践
- 管理感情:精力有限,要么干活,要么内斗
- Acronis Disk Director 增大c盘
- 计算机原理电梯控制系统设计,基于PLC的电梯控制系统的设计与研究
- 使用JavaScript创建模块化的双人对战象棋程序
- android 使用adb命令安装安卓apk包
- 科研必备 | 谷歌学术高级搜索详解
- C300 之SFU设备配置指导
- Python爬取招聘网站