一篇文章理解所有android关于存储的方法
2016-06-16 21:00
507 查看
转自大神:http://www.liaohuqiu.net/cn/posts/storage-in-android/
android系统自身自带有存储,另外也可以通过sd卡来扩充存储空间。前者好比pc中的硬盘,后者好移动硬盘。 前者空间较小,后者空间大,但后者不一定可用。 开发应用,处理本地数据存取时,可能会遇到这些问题:
需要判断sd卡是否可用: 占用过多机身内部存储,容易招致用户反感,优先将数据存放于sd卡;
应用数据存放路径,同其他应用应该保持一致,应用卸载时,清除数据:
标新立异在sd卡根目录建一个目录,招致用户反感
用户卸载应用后,残留目录或者数据在用户机器上,招致用户反感
需要判断两者的可用空间: sd卡存在时,可用空间反而小于机身内部存储,这时应该选用机身存储;
数据安全性,本应用数据不愿意被其他应用读写;
图片缓存等,不应该被扫描加入到用户相册等媒体库中去。
使用外部存储,需要的权限,在
从API 19 / Andorid 4.4 / KITKAT开始,不再需要显式声明这两个权限,除非要读写其他应用的应用数据(
判断sd卡可用:
根据系统用户不同,所能占用的存储空间大小也有不同
在API level 9及其以上时,
当有多个存储可用时获取磁盘用量,根据当前系统情况选用合适的存储。
根据系统存储用量,合理设定app所用的空间大小;运行时,也可做动态调整。
在API level 9及其以上的系统,可直接调用
一般地,通过
通过这两个类可获取各种路径,如图:
下面介绍这些路径的特性以及使用中需要注意的细节:
根目录(
内部存储路径:
通过
外部存储路径:
/mnt/ 这样的),通过
示例:
应用数据目录(
内部储存:
外部存储:
在这些目录下的数据,在app卸载之后,会被系统删除,我们应将应用的数据放于这两个目录中。
外部存储中,公开的数据目录。 这些目录将不会随着应用的删除而被系统删除,请斟酌使用:
应用数据目录下的目录
一般的在$appDataDir下,会有两个目录:
数据缓存:
内部存储:
机身内存不足时,文件会被删除
外部存储:
外部存储没有实时监控,当空间不足时,文件不会实时被删除,可能返回空对象
示例:
文件目录
内部存储:通过
示例:
外部存储:通过
示例:
在内部存储中,
在外部存储中,这两个文件夹其他应用程序也可访问。
在外部存储中,
在内部存储中:通过
目录的命名规则为
示例:
特别注意, 对于外部存储,获取
在API level 8 以下,或者空间不足,相关的方法获路径为空时,需要自己构造。
可能遇到的问题
android系统自身自带有存储,另外也可以通过sd卡来扩充存储空间。前者好比pc中的硬盘,后者好移动硬盘。 前者空间较小,后者空间大,但后者不一定可用。 开发应用,处理本地数据存取时,可能会遇到这些问题:需要判断sd卡是否可用: 占用过多机身内部存储,容易招致用户反感,优先将数据存放于sd卡;
应用数据存放路径,同其他应用应该保持一致,应用卸载时,清除数据:
标新立异在sd卡根目录建一个目录,招致用户反感
用户卸载应用后,残留目录或者数据在用户机器上,招致用户反感
需要判断两者的可用空间: sd卡存在时,可用空间反而小于机身内部存储,这时应该选用机身存储;
数据安全性,本应用数据不愿意被其他应用读写;
图片缓存等,不应该被扫描加入到用户相册等媒体库中去。
基本操作
使用外部存储,需要的权限,在AndoridManifest.xml中:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
从API 19 / Andorid 4.4 / KITKAT开始,不再需要显式声明这两个权限,除非要读写其他应用的应用数据(
$appDataDir)
判断sd卡可用:
/** * Check if the primary "external" storage device is available. * * @return */ public static boolean hasSDCardMounted() { String state = Environment.getExternalStorageState(); if (state != null && state.equals(Environment.MEDIA_MOUNTED)) { return true; } else { return false; } }
存储的用量情况
根据系统用户不同,所能占用的存储空间大小也有不同在API level 9及其以上时,
File对象的
getFreeSpace()方法获取系统root用户可用空间;
getUsableSpace()取非root用户可用空间
当有多个存储可用时获取磁盘用量,根据当前系统情况选用合适的存储。
根据系统存储用量,合理设定app所用的空间大小;运行时,也可做动态调整。
在API level 9及其以上的系统,可直接调用
File对象的相关方法,以下需自行计算:
@TargetApi(VERSION_CODES.GINGERBREAD) public static long getUsableSpace(File path) { if (path == null) { return -1; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { return path.getUsableSpace(); } else { if (!path.exists()) { return 0; } else { final StatFs stats = new StatFs(path.getPath()); return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks(); } } }
路径的规律
一般地,通过Context和
Environment相关的方法获取文件存取的路径。
通过这两个类可获取各种路径,如图:
($rootDir) +- /data -> Environment.getDataDirectory() | | | | ($appDataDir) | +- data/com.srain.cube.sample | | | | ($filesDir) | +- files -> Context.getFilesDir() / Context.getFileStreamPath("") | | | | | +- file1 -> Context.getFileStreamPath("file1") | | ($cacheDir) | +- cache -> Context.getCacheDir() | | | +- app_$name ->(Context.getDir(String name, int mode) | | ($rootDir) +- /storage/sdcard0 -> Environment.getExternalStorageDirectory() | / Environment.getExternalStoragePublicDirectory("") | +- dir1 -> Environment.getExternalStoragePublicDirectory("dir1") | | ($appDataDir) +- Andorid/data/com.srain.cube.sample | | ($filesDir) +- files -> Context.getExternalFilesDir("") | | | +- file1 -> Context.getExternalFilesDir("file1") | +- Music -> Context.getExternalFilesDir(Environment.Music); | +- Picture -> ... Environment.Picture | +- ... | | ($cacheDir) +- cache -> Context.getExternalCacheDir() | +- ???
各个路径的特性
下面介绍这些路径的特性以及使用中需要注意的细节:根目录(
$rootDir):
内部存储路径:
/data,
通过
Environment.getDataDirectory()获取
外部存储路径:
/storage/sdcard0(也有类似
/mnt/ 这样的),通过
Environment.getExternalStorageDirectory()获取
示例:
Environment.getDataDirectory(): /data Environment.getExternalStorageDirectory(): /storage/sdcard0
应用数据目录(
$appDataDir)
内部储存:
$appDataDir = $rootDir/data/$packageName,
外部存储:
$appDataDir = $rootDir/Andorid/data/$packageName
在这些目录下的数据,在app卸载之后,会被系统删除,我们应将应用的数据放于这两个目录中。
外部存储中,公开的数据目录。 这些目录将不会随着应用的删除而被系统删除,请斟酌使用:
Environment.getExternalStorageDirectory(): /storage/sdcard0 // 同 $rootDir Environment.getExternalStoragePublicDirectory(""): /storage/sdcard0 Environment.getExternalStoragePublicDirectory("folder1"): /storage/sdcard0/folder1
应用数据目录下的目录
一般的在$appDataDir下,会有两个目录:
数据缓存:
$cacheDir = $appDataDir/cache:
内部存储:
Context.getCacheDir(),
机身内存不足时,文件会被删除
外部存储:
Context.getExternalCacheDir()
外部存储没有实时监控,当空间不足时,文件不会实时被删除,可能返回空对象
示例:
Context.getCacheDir(): /data/data/com.srain.cube.sample/cache Context.getExternalCacheDir(): /storage/sdcard0/Android/data/com.srain.cube.sample/cache
文件目录
$filesDir = $appDataDir/files:
内部存储:通过
Context.getFilesDir()获取
Context.getFileStreamPath(String name)返回以
name为文件名的文件对象,
name为空,则返回
$filesDir本身
示例:
Context.getFilesDir(): /data/data/com.srain.cube.sample/files Context.getFileStreamPath(""): /data/data/com.srain.cube.sample/files Context.getFileStreamPath("file1"): /data/data/com.srain.cube.sample/files/file1
外部存储:通过
Context.getExternalFilesDir(String type),
type为空字符串时获取.
type系统指定了几种类型:
Environment.DIRECTORY_MUSIC Environment.DIRECTORY_PICTURES ...
示例:
Context.getExternalFilesDir(""): /storage/sdcard0/Android/data/com.srain.cube.sample/files Context.getExternalFilesDir(Environment.DIRECTORY_MUSIC) /storage/sdcard0/Android/data/com.srain.cube.sample/files/Music
$cacheDir / $filesDir安全性
在内部存储中,
$cacheDir,
$filesDir是app安全的,其他应用无法读取本应用的数据,而外部存储则不是。
在外部存储中,这两个文件夹其他应用程序也可访问。
在外部存储中,
$filesDir中的媒体文件,不会被当做媒体扫描出来,加到媒体库中。
$cacheDir / $filesDir同级目录
在内部存储中:通过
Context.getDir(String name, int mode)可获取和
$filesDir/
$cacheDir同级的目录
目录的命名规则为
app_ + name, 通过mode可控制此目录为app私有还是其他app可读写。
示例:
Context.getDir("dir1", MODE_PRIVATE): Context.getDir: /data/data/com.srain.cube.sample/app_dir1
特别注意, 对于外部存储,获取
$cacheDir或者
$filesDir及其下的路径
在API level 8 以下,或者空间不足,相关的方法获路径为空时,需要自己构造。
@TargetApi(VERSION_CODES.FROYO) public static File getExternalCacheDir(Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO)) { File path = context.getExternalCacheDir(); // In some case, even the sd card is mounted, // getExternalCacheDir will return null // may be it is nearly full. if (path != null) { return path; } } // Before Froyo or the path is null, // we need to construct the external cache folder ourselves final String cacheDir = "/Android/data/" + context.getPackageName() + "/cache/"; return new File(Environment.getExternalStorageDirectory().getPath() + cacheDir); }
相关文章推荐
- 一篇文章理解所有android关于存储的方法
- Android中Context详解
- 设置不要缓存cookie
- HandlerThread
- Android toolbar menu 字体点击样式
- Android 热更新实现原理及代码分析
- Android 常用知识总结2
- Android的Touch Mode
- Android自助餐之解析zip
- Android粒子雨效果之音量条显示
- Andro 4000 id内存泄漏(Handler造成的内存泄漏(一))
- Android 高低版本中的一些差异性
- 学习Android,做报告的感想
- Android布局优化——merge与ViewStub
- Android 自动填写短信验证码 两种实现(二)
- 使用AndroidStudio进行NDK开发简单配置
- RecyclerView android:layout_width="match_parent"无效
- Android Sax解析XML出现空值或脏数据的解决方案
- Android RecyclerView 完全解析
- Android中的内存泄露(一.内存泄漏的认识以及LeakCannry的基本用法)