android 内外置SD卡的研究
来源:互联网 发布:java打印杨辉三角10行 编辑:程序博客网 时间:2024/04/28 03:32
以前的Android(4.1之前的版本)中,SDcard跟路径通过“/sdcard”或者“/mnt/sdcard”来表示存储卡,而在Jelly Bean系统中修改为了“/storage/sdcard0”,以后可能还会有多个SDcard的情况。
目前为了保持和之前代码的兼容,sdcard路径做了link映射。
为了使您的代码更加健壮并且能够兼容以后的Android版本和新的设备,请通过Environment.getExternalStorageDirect
1、通用的获取语句
Environment.getExternalStorageDirectory().getPath()当外置sd卡不存在的情况下,这条语句是获取的内置sd卡的路径。外置sd卡存在,获取是外置sd卡。获取出来的值是/storage/sdcard0
2、那么内置sd卡是怎样的
public static String getSoftwareStorageDirectory() {Map<String,String> sysInfo=System.getenv();//获取外置的sd卡String sd_defult = sysInfo.get("SECONDARY_STORAGE"); return sd_defult;}获取出来的值是/storage/sdcard1,看序号一个是0,一个是1。我在网上看到有人说,这种获取方法,在api23中将不存在,我还没验证,没有相应 的机子测试,以及查看api23的源码。就是这个字段在API 23版本中 SECONDARY_STORAGE 被移除。这种获取方法也是类似于源码获取方式。
调试时候Map<String,String> sysInfo=System.getenv();,这句语句获取出来的值如下:
{ANDROID_SOCKET_zygote=9, SECONDARY_STORAGE=/storage/sdcard1,ANDROID_STORAGE=/storage, ANDROID_BOOTLOGO=1,EXTERNAL_STORAGE=/storage/sdcard0,ANDROID_ASSETS=/system/app,ASEC_MOUNTPOINT=/mnt/asec, PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin,LOOP_MOUNTPOINT=/mnt/obb, BOOTCLASSPATH=/system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/mediatek-common.jar:/system/framework/mediatek-framework.jar:/system/framework/secondary-framework.jar:/system/framework/CustomProperties.jar:/system/framework/mediatek-telephony-common.jar:/system/framework/mediatek-op.jar, ANDROID_DATA=/data, ANDROID_PROPERTY_WORKSPACE=8,49664,ANDROID_ROOT=/system,LD_LIBRARY_PATH=/vendor/lib:/system/lib}
api17源码,部分源码Environment
private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE"; private static final String ENV_EMULATED_STORAGE_SOURCE = "EMULATED_STORAGE_SOURCE"; private static final String ENV_EMULATED_STORAGE_TARGET = "EMULATED_STORAGE_TARGET"; private static final String ENV_MEDIA_STORAGE = "MEDIA_STORAGE";
public UserEnvironment(int userId) { // See storage config details at http://source.android.com/tech/storage/ String rawExternalStorage = System.getenv(ENV_EXTERNAL_STORAGE); String rawEmulatedStorageTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET); String rawMediaStorage = System.getenv(ENV_MEDIA_STORAGE); if (TextUtils.isEmpty(rawMediaStorage)) { rawMediaStorage = "/data/media"; } if (!TextUtils.isEmpty(rawEmulatedStorageTarget)) { // Device has emulated storage; external storage paths should have // userId burned into them. final String rawUserId = Integer.toString(userId); final File emulatedBase = new File(rawEmulatedStorageTarget); final File mediaBase = new File(rawMediaStorage); // /storage/emulated/0 mExternalStorage = buildPath(emulatedBase, rawUserId); // /data/media/0 mMediaStorage = 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/sdcard0 mExternalStorage = new File(rawExternalStorage); // /data/media mMediaStorage = new File(rawMediaStorage); } mExternalStorageAndroidObb = buildPath(mExternalStorage, DIRECTORY_ANDROID, "obb"); mExternalStorageAndroidData = buildPath(mExternalStorage, DIRECTORY_ANDROID, "data"); mExternalStorageAndroidMedia = buildPath(mExternalStorage, DIRECTORY_ANDROID, "media"); }
在上面的源码当中String sdcardPath = System.getenv("EXTERNAL_STORAGE"); 获取也是外置sd卡。
可是在源码中也是没有看到String extSdcardPath = System.getenv("SECONDARY_STORAGE"); 。SECONDARY_STORAGE这个变量是没有,我也纳闷,怎么也可以使用。这就有点疑问了。
获取外置sd卡是否存在的源码/** * Gets the current state of the primary "external" storage device. * * @see #getExternalStorageDirectory() */ public static String getExternalStorageState() { try { IMountService mountService = IMountService.Stub.asInterface(ServiceManager .getService("mount")); final StorageVolume primary = getPrimaryVolume(); return mountService.getVolumeState(primary.getPath()); } catch (RemoteException rex) { Log.w(TAG, "Failed to read external storage state; assuming REMOVED: " + rex); return Environment.MEDIA_REMOVED; } }一些映射关系
private static StorageVolume getPrimaryVolume() { if (sPrimaryVolume == null) { synchronized (sLock) { if (sPrimaryVolume == null) { try { IMountService mountService = IMountService.Stub.asInterface(ServiceManager .getService("mount")); final StorageVolume[] volumes = mountService.getVolumeList(); sPrimaryVolume = StorageManager.getPrimaryVolume(volumes); } catch (Exception e) { Log.e(TAG, "couldn't talk to MountService", e); } } } } return sPrimaryVolume; }那么,在android上是怎么判断的。
/** * getExternalStorageState() returns MEDIA_CHECKING if the media is present and being disk-checked * 要获取SD卡首先要确认SD卡是否装载 * @return */public boolean getExternalStorageState(){return Environment.getExternalStorageState().equals(Environment.MEDIA_CHECKING); }判断是都可以读写
/** * getExternalStorageState() returns MEDIA_MOUNTED * if the media is present and mounted at its mount point with read/write access. * 要获取SD卡是否可以读写 * @return */public boolean getExternalStorageStateMOUNTED(){return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); }这里判断读写跟判断是都存在是有歧义的,我测试时候,没有放sd卡,判断读写是可以的,可是外置sd卡根本不存在。写程序时候是不是先要判断存在,再判断能不能读写。
还有一个问题就是,既然外置sd卡不存在时候Environment.getExternalStorageDirectory().getPath()这条语句获取的是内置的sd卡,那么判断是否是内置sd卡的读写呢?
3、网上看到最多获取外置SD卡路径两个方法
方法一
/** * 获取外置SD卡路径 * * @return 应该就一条记录或空 */public List getExtSDCardPath() {List lResult = new ArrayList();try {Runtime rt = Runtime.getRuntime();Process proc = rt.exec("mount");InputStream is = proc.getInputStream();InputStreamReader isr = new InputStreamReader(is);BufferedReader br = new BufferedReader(isr);String line;//rootfs / rootfs ro,relatime 0 0while ((line = br.readLine()) != null) {if (line.contains("extSdCard")) {String[] arr = line.split(" ");String path = arr[1];File file = new File(path);if (file.isDirectory()) {lResult.add(path);}}}isr.close();} catch (Exception e) {}return lResult;}
方法二
//获取外置存储卡的根路径,如果没有外置存储卡,则返回null public String getExtSDCardPath2() {String sdcard_path = null;String sd_default = Environment.getExternalStorageDirectory().getAbsolutePath();if (sd_default.endsWith("/")) {sd_default = sd_default.substring(0, sd_default.length() - 1);}// 得到路径try {Runtime runtime = Runtime.getRuntime();Process proc = runtime.exec("mount");InputStream is = proc.getInputStream();InputStreamReader isr = new InputStreamReader(is);String line;BufferedReader br = new BufferedReader(isr);//rootfs / rootfs ro,relatime 0 0while ((line = br.readLine()) != null) {if (line.contains("secure"))continue;if (line.contains("asec"))continue;if (line.contains("fat") && line.contains("/mnt/")) {String columns[] = line.split(" ");if (columns != null && columns.length > 1) {if (sd_default.trim().equals(columns[1].trim())) {continue;}sdcard_path = columns[1];}} else if (line.contains("fuse") && line.contains("/mnt/")) {String columns[] = line.split(" ");if (columns != null && columns.length > 1) {if (sd_default.trim().equals(columns[1].trim())) {continue;}sdcard_path = columns[1];}}}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}return sdcard_path;}我用机子测试时候,获取出来的值都是//rootfs / rootfs ro,relatime 0 0
根本没有想要的。
manifest权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
最后总结一下
Environment.getExternalStorageDirect
不过app应用来说是需要固定一个路径的。
我现在使用的是
public String getSoftwareStorageDirectory() {String strDirectory;Map<String,String> sysInfo=System.getenv();String sd_defult = sysInfo.get("SECONDARY_STORAGE");if (!CheckDirectoryExists(sd_defult)){sd_defult = Environment.getExternalStorageDirectory().getPath();} return strDirectory;}//判断检出目录是否存在private boolean CheckDirectoryExists(String fileName) {if (fileName == null || fileName.length()<=0) {return false;}File temFile = new File(fileName);File[] childFiles = null;if (temFile != null)childFiles = temFile.listFiles();if (childFiles == null) {return false;}//目录是否可以写File testFile = new File(temFile, "com_testDir");if (!testFile.exists()) {if (!testFile.mkdir()) {return false;}testFile.delete();}return true;}
欢迎大家测试,提供不同机子的测试结果,还有不同源码下是怎样的。
因为有不同厂商,或者用户是刷机,所以有很多奇葩的路径也不足为奇。
- android 内外置SD卡的研究
- android 2.3 取内外置SD卡
- android 获取外置SD卡的路径
- android获取外置SD卡的路径
- android 4.0 取内外置SD卡新特性
- android 4.0 取内外置SD卡新特性
- 权限android.permission.WRITE_EXTERNAL_STORAGE 内外置sd卡写权限
- android两行代码获取内外置sd卡路径
- Android 获取外置SD卡
- 获取外置的SD卡
- Android手机外置SD卡(TF卡)的获取方法
- 获得Android系统外置SD卡的路径
- android 获取外置SD卡的路径(非挫版)
- 获得Android系统外置SD卡的路径
- android 获取外置SD卡的路径(非挫版)
- android 获取外置SD卡的路径(非挫版)
- Android对外置sd卡的权限问题(上)
- Android获取内置和外置sd卡路径的方法
- 《面向对象程序设计》课程设计报告 题目:《记忆测试系统》课程设计
- js检测上传文件大小(ie中判断文件上传兼容)
- 单片机学习(一)__led灯
- 浏览器和服务器在基于https进行请求链接到数据传输过程中,用到了如下哪些技术
- QT 5.8 新特性
- android 内外置SD卡的研究
- Educational Codeforces Round 2 D. Area of Two Circles' Intersection
- 【虚拟按键】虚拟键适配PopupWindow显示位置
- 【NOIP模拟】千帆渡
- 标注文件格式转换功能的简单实现
- JavaScript强化教程 —— Cocos2d-JS自动JSB绑定规则修改
- 1041. Be Unique (20)
- 文件
- gem5模拟器安装