Android的外部存储
Android支持外部存储(case-insensitive filesystem with immutable POSIX permission classes and modes)。
外部存储可以通过物理介质提供(如SD卡),也可以通过将内部存储中的一部分封装而成,设备可以有多个外部存储实例。
访问外部存储的权限
从Android 1.0开始,写操作受权限WRITE_EXTERNAL_STORAGE保护。
从Android 4.1开始,读操作受权限READ_EXTERNAL_STORAGE保护。
从Android 4.4开始,应用可以管理在它外部存储上的特定包名目录,而不用获取WRITE_EXTERNAL_STORAGE权限。
比如,一个包名为com.example.foo的应用,可以自由访问外存上的Android/data/com.example.foo/目录。
外部存储对数据提供的保护较少,所以系统不应该存储敏感数据在外部存储上。
特别地,配置和log文件应该存储在内部存储中,这样它们可以被有效地保护。
对于多用户的情况,一般每个用户都会有自己独立的外部存储,应用仅对当前用户的外部存储有访问权限。
Environment API的目录
getDataDirectory():用户数据目录。
getDownloadCacheDirectory():下载缓存内容目录。
getExternalStorageDirectory():主要的外部存储目录。
但是这个目录很可能当前不能访问,比如这个目录被用户的PC挂载,或者从设备中移除,或者其他问题发生,你可以通过getExternalStorageState()来获取当前状态。
还有多用户或者多外部存储的情况,此文不再讨论。
为了不污染用户的根命名空间,一般不会直接使用这个外部存储的根目录。
任何应用私有的文件的应该被放置在 Context.getExternalFilesDir返回的目录下,在应用被卸载的时候,系统会清理的就是这个目录。
另一些共享文件应该被放置在 getExternalStoragePublicDirectory(String)
返回的目录中。
写这个路径需要 WRITE_EXTERNAL_STORAGE
权限,读需要 READ_EXTERNAL_STORAGE
权限,当然写权限默认包含了读权限。
从KITKAT 即Android 4.4开始,如果你的应用只是需要存储一些内部数据,可以考虑使用 :
getExternalFilesDir(String)
或者getExternalCacheDir(),它们不需要获取权限。
getExternalStoragePublicDirectory(String type)这个方法接收一个参数,表明目录所放的文件的类型,传入的参数是Environment类中的DIRECTORY_XXX静态变量,比如DIRECTORY_DCIM等。
注意:传入的类型参数不能是null,返回的目录路径有可能不存在,所以必须在使用之前确认一下,比如使用File.mkdirs创建该路径。
getRootDirectory()得到Android的根目录。
isExternalStorageEmulated()设备的外存是否是用内存模拟的,是则返回true。(API Level 11)
isExternalStorageRemovable()设备的外存是否是可以拆卸的,比如SD卡,是则返回true。(API Level 9)
Context API中的目录
getExternalFilesDir(String type)是应用在外部存储上的目录。
和Environment类的getExternalStoragePublicDirectory(String type)方法类似,返回包含参数指定的特定类型文件的子目录。
getExternalCacheDir()是应用的在外部存储上的缓存目录。
从Android 4.4这两个方法不需要读写权限,是针对于本应用来说,如果要访问其他应用的相关目录,还是需要声明读写权限。
Android 4.4之前的版本要访问的话还是要声明读写权限的,如果没有在manifest中写权限,上面两个get方法都会返回null。
与上面两个方法形成对比的是下面两个方法:
这两个方法得到的是内存上的目录。
这些目录都是属于应用的,当应用被卸载的时候,里面的内容都会被移除,但是不要依赖于系统的操作。
getCacheDir()方法用于获取/data/data/<applicationpackage>/cache目录 (应用缓存)
getFilesDir()方法用于获取/data/data/<applicationpackage>/files目录
//下面两个方法是否能够在程序被卸载时被删除与API的等级有关
Context.getExternalFilesDir()方法可以获取到SDCard/Android/data/你的应用的包名/files/目录,一般放一些长时间保存的数据
Context.getExternalCacheDir()方法可以获取到SDCard/Android/data/你的应用包名/cache/目录,一般存放临时缓存数据
/data/data/package_name/database/webview.db*(WebView缓存)
/data/data/package_name/database/webviewCache.db*(WebView缓存)
public class utils { /** * 缓存大小 * @param context * @return * @throws Exception */ public static String getTotalCacheSize(Context context) throws Exception { long cacheSize = getFolderSize(context.getCacheDir()); if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { cacheSize += getFolderSize(context.getExternalCacheDir()); } return getFormatSize(cacheSize); } /** * 清空缓存 * @param context */ public static void clearAllCache(Context context) { UtilsLog.d(); /** * 清除本应用内部缓存(/data/data/com.xxx.xxx/cache) */ //这样 deleteDir(context.getCacheDir()); //这样 本应用数据清除 deleteDir(new File("/data/data/"+context.getPackageName()+"/cache"));// /** * 清除本应用所有数据库(/data/data/com.xxx.xxx/databases) */ //还可以这样 deleteDir(new File("/data/data/"+context.getPackageName()+"/databases"));// /** * 清除本应用SharedPreference(/data/data/com.xxx.xxx/shared_prefs) */ deleteDir(new File("/data/data/"+context.getPackageName()+"/shared_prefs"));// /** * 清除/data/data/com.xxx.xxx/files */ deleteDir(context.getFilesDir()); deleteDir(new File("/data/data/"+context.getPackageName()+"/files"));// /** * mnt/sdcard/android/data/com.xxx.xxx/ */ deleteDir(new File(Constant.LOCAL_URL)); UtilsLog.d(); if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { /** * mnt/sdcard/android/data/com.xxx.xxx/cache */ deleteDir(context.getExternalCacheDir()); } } private static boolean deleteDir(File dir) { if (dir != null && dir.isDirectory()) { String[] children = dir.list(); if(children== null) return false; for (int i = 0; i < children.length; i++) { UtilsLog.d(children[i]); boolean success = deleteDir(new File(dir, children[i])); if (!success) { return false; } } } return dir.delete(); } // 获取文件 // Context.getExternalFilesDir() --> SDCard/Android/data/你的应用的包名/files/ // 目录,一般放一些长时间保存的数据 // Context.getExternalCacheDir() --> // SDCard/Android/data/你的应用包名/cache/目录,一般存放临时缓存数据 public static long getFolderSize(File file) throws Exception { long size = 0; try { File[] fileList = file.listFiles(); for (int i = 0; i < fileList.length; i++) { // 如果下面还有文件 if (fileList[i].isDirectory()) { size = size + getFolderSize(fileList[i]); } else { size = size + fileList[i].length(); } } } catch (Exception e) { e.printStackTrace(); } return size; } /** * 格式化单位 * * @param size * @return */ public static String getFormatSize(double size) { double kiloByte = size / 1024; if (kiloByte < 1) { // return size + "Byte"; return "0K"; } double megaByte = kiloByte / 1024; if (megaByte < 1) { BigDecimal result1 = new BigDecimal(Double.toString(kiloByte)); return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "KB"; } double gigaByte = megaByte / 1024; if (gigaByte < 1) { BigDecimal result2 = new BigDecimal(Double.toString(megaByte)); return result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "MB"; } double teraBytes = gigaByte / 1024; if (teraBytes < 1) { BigDecimal result3 = new BigDecimal(Double.toString(gigaByte)); return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "GB"; } BigDecimal result4 = new BigDecimal(teraBytes); return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB"; } }
参考
http://www.2cto.com/kf/201503/385492.html
http://www.cnblogs.com/rayray/p/3413673.html
http://www.cnblogs.com/mengdd/p/3742623.html