storage路径问题
1 概念总述
android开发中,关于存储路径,我们经常听到以下几个概念:内存、内部存储和外部存储,现在我们就来详细说说这三者区别与联系。
内存:英文中记为memory,即RAM
内部存储:英文记为InternalStorage,即内部ROM
外部存储:英文记为ExternalStorage, 即外部ROM和SDCard
由上可知三者在英文中不会产生太大的歧义,但是当我们翻译为中文后,对于三者之间的关系就开始模糊化了。最容易混淆的是外部存储,我们普遍认为机身固有的存储是内部存储,而扩展的T卡是外部存储。早期的android设备内部存储确实是固定的,而外部存储确实是可以像U盘一样移动的。但是在后来的设备中,很多中高端的机器都将自己的机身存储扩展到了8G以上,他们将存储在概念上分成了"内部internal"和"外部external"两部分,但其实都在手机内部。所以不管android手机是否有可移动的sdcard,他们总是有外部存储和内部存储。最关键的是,我们都是通过相同的api来访问可移动的sdcard或者手机自带的存储。
Android 内存
手机的整个存储空间分为内部存储和外部存储两部分,内部存储中又包含RAM和ROM等部分。
内部存储,即InternalStorage,也常说内置存储卡,这是手机内置的存储空间,出厂时就被确定,是手机的一个硬件指标。类比电脑的内存。
外部存储,即ExternalStorage,也常说外置存储卡,手机出厂时并不存在,是由用户自由扩展的存储空间,常见的就是SD卡。类比电脑的外接移动硬盘。
RAM,即常说的运行时内存,是手机运行时存储数据和指令的地方,注意是运行时内存。类比电脑的内存条。
ROM,用来存放一些系统文件,应用配置和其他数据的地方,是内部存储中主要存储区域。类比于Windows电脑的C盘。
在 Android Studio 使用 DDMS 的 File Exploer 窗口中查看文件系统,下图就是一个 Android 文件系统目录。
Android 文件系统目录
这里有三个文件夹需要注意,data、mnt和storage,data是指内部存储,mnt和storage指外部存储。下面将详细介绍内部存储和外部存储。
2 内部存储
内部存储位于系统中很特殊的一个位置,如果你想将文件存储于内部存储中,那么文件默认只能被你的应用访问到,且一个应用创建的所有文件都在和应用包名相同的目录下。当一个应用卸载后,内部存储中的这些文件也被删除。内部存储空间十分有限,它是系统本身和系统应用程序主要的数据存储所在地,一旦内部存储空间耗尽,手机就无法使用了。Shared Preferences和SQLite数据库都是存储在内部存储空间上的。内部存储一般用Context来获取和操作。内部存储有两个重要目录:
1)app文件夹:没有root的手机不能打开该文件夹。app文件夹里存放着系统中安装的第三方应用的apk文件,当我们调试一个app的时候,可以看到控制台输出的内容,有一项是uploading...,就是上传我们的apk到这个文件夹,上传成功后才开始安装。
2)data文件夹:
该文件夹存放存储包私有数据,对于设备中每一个安装的 App,系统都会在内部存储空间的 data/data 目录下以应用包名为名字自动创建与之对应的文件夹。
用户卸载 App 时,系统自动删除 data/data 目录下对应包名的文件夹及其内容。
该目录下又把存储内容进行了分类:
- data/data/包名/cache: 存放的 APP 的缓存信息
- data/data/包名/databases: 存放 APP 的数据库信息
- data/data/包名/files: 存放 APP 的文件信息
- data/data/包名/shared_prefs: 存放 APP 内的 SharedPreferences
3)路径获取API
/data Environment.getDataDirectory();
/data/data/包名/files context.getFilesDir();
//对于 Files 目录下的文件,通常不会通过 File 类的方式直接进行读写,而是利用一些封装过的类或函数进行操作: public FileInputStream openFileInput(String name) public FileOutputStream openFileOutput(String name, int mode)
//还可以直接删除或查询该目录下的文件: context.deleteFile(name) context.fileList()
/data/data/包名/cache context.getCacheDir();
/data/data/包名/shared_prefs context.getSharedPreferences(name,mode)//返回的是 SharedPreferences 对象 context.deleteSharedPreferences(name)
/data/data/包名/databases context.getDataDir() context.getDatabasePath(name) context.deleteDatabase(name)
/data/data/包名/app_name context.getDir(name,mode) //经测试该方法会在 /data/data/包名/ 目录下生成一个以 app_ 开头的目录
3 外部存储
每个兼容 Android 的设备都支持可用于保存文件的共享“外部存储”。 该存储可能是可移除的存储介质(例如 SD 卡)或内部(不可移除)存储。 保存到外部存储的文件是全局可读取文件,而且,在计算机上启用 USB 大容量存储以传输文件后,可由用户修改这些文件。
Environment.getExternalStorageState()
返回值为以下几种:
MEDIA_MOUNTED:sd卡正常挂载
MEDIA_REMOVED:无介质
MEDIA_UNMOUNTED:有介质,未挂载,在系统中删除
MEDIA_BAD_REMOVAL:介质在挂在前被移除,直接取出sd卡。
MEDIA_CHECKING:正在磁盘检查,刚装上sd卡时
MEDIA_SHARED:sd卡存在但没有挂载,并且通过USB大容量存储共享,操作打开USB存储
MEDIA_MOUNTED_READ_ONLY:sd卡存在并且已挂载,但是挂载方式为只读
MEDIA_NOFS:介质存在但是为空白,或用在不支持的文件系统
MEDIA_UNMOUNTABLE:存在sd卡但是不能挂载,例如发生介质损坏
挂载:这是linux系统的术语,就是加载的意思,把sd卡划入系统相连,让系统能认到并读取sd卡的内容。
当sd卡状态为MEDIA_MOUNTED时,/mnt/sdcard目录才是可读可写,并且可以创建目录及文件。其他情况一律不可读可写。
读取sd卡一般会这么写。
String state; String path; state = Environment.getExternalStorageState(); if(state.equals(Environment.MEDIA_MOUNTED)){ path = Environment.getExternalStorageDirectory().getAbsolutePath(); }
读写sd卡不要忘了权限问题,需加入以下两个权限
* 1 在AndroidManifest文件中加入sdcard操作权限 <!--在SDCard中创建与删除文件权限 --> <uses-permissioandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <!--往SDCard写入数据权限 --> <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/> * 2 确认sdcard的存在 android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED) * 3 获取扩展存储设备的文件目录 android.os.Environment.getExternalStorageDirectory();
Android 在外部存储上提供了十个公共目录来存储相对应的文件:
通过 API Environment.getExternalStoragePublicDirectory(type)
来访问
- DIRECTORY_MUSIC:
/storage/emulated/0/Music
- DIRECTORY_PODCASTS:
/storage/emulated/0/Podcasts
- DIRECTORY_RINGTONES:
/storage/emulated/0/Ringtones
- DIRECTORY_ALARMS:
/storage/emulated/0/Alarms
- DIRECTORY_NOTIFICATIONS:
/storage/emulated/0/Notifications
- DIRECTORY_PICTURES:
/storage/emulated/0/Pictures
- DIRECTORY_MOVIES:
/storage/emulated/0/Movies
- DIRECTORY_DOWNLOADS:
/storage/emulated/0/Downloads
- DIRECTORY_DCIM:
/storage/emulated/0/Dcim
- DIRECTORY_DOCUMENTS:
/storage/emulated/0/Documents
3)私有目录
Android2.2 引入了基于扩展存储器的应用缓存目录,该目录指向大容量的扩展存储器。与应用的内存私有目录一样,缓存目录会随着应用的卸载一并删除。
和内部存储一样,会在 SD 卡的 Android/data 目录下生成对应包名的文件夹
/storage/emulated/0/Android/data/应用包名/files context.getExternalFilesDir(type)
/storage/emulated/0/Android/data/应用包名/cache context.getExternalCacheDir()
在 Android 目录下除了 data 目录还有一个 obb 目录 /storage/emulated/0/Android/obb/应用包名 context.getObbDir()
4)其他目录
- /cache 目录
通过 APIEnvironment.getDownloadCacheDirectory()
访问,存储下载文件的缓存路径 - /system 目录
通过 APIEnvironment.getRootDirectory()
访问,该目录下也有一个 app 目录,存放的是系统应用的 apk 文件。
/system/app 和 /data/app 的区别
- /data/app 里软件权限没全开,/system/app 里的软件获取了所有权限
- /data/app 可以应用卸载,/system/app 只能 root 后删除
- /data/app 文件夹大小随便,/system/app 文件夹有大小限制
- 卸载/system/app 目录下的文件并不会增加系统空间,即可用 ROM 空间
-
/mnt 目录
这个目录专门用来当作挂载点挂在外部设备的,如 SD 卡,sdcard
将会被系统视作一个文件夹,这个文件夹将会被系统嵌入到收集系统的 mnt 目录中,所以在 /mnt 目录下也会看到一个 sdcard 的快捷方式:
4 总结
A: getCacheDir(): 获取/data/data//cache目录
getFileDir(): 获取/data/data/files目录
这两个目录中的内容必须是root的手机在文件操作系统中才能看到。当然如果在应用程序中清空数据或者卸载应用,那么这两个目录下的文件也将会被清空的。
B: getExternalFilesDir(): 获取SDCard/Android/data/你的应用的包名/files/目录(一般存放一些长时间保存的数据)
getExternalCacheDir(): 获取SDCard/Android/data/你的应用包名/cache/目录(一般存放临时缓存的数据)
这两个是放在外置存储卡的,这个目录下的内容,可以使用文件浏览系统查看到,但是如果清空数据或者卸载应用,这两个目录下的文件也将被清空。
当应用被用户卸载后,SDCard/Android/data/你的应用包名/这个目录下的所有文件都会被删除,不会留下垃圾信息。A、B两种方式的缓存都会在卸载app的时候被系统清理到,而开发者自己在sd卡上建立的缓存文件夹,是不会随着app的卸载而被清除掉的。
getCacheDir:/data/data/com.example.sinatext/cache getFilesDir:/data/data/com.example.sinatext/files getExternalCacheDir:/storage/sdcard0/Android/data/com.example.sinatext/cache getExternalFilesDir:/storage/sdcard0/Android/data/com.example.sinatext/files/text getDatabasePath:/data/data/com.example.sinatext/databases/text getDir:/data/data/com.example.sinatext/app_modeDir getPackageResourcePath:/data/app/com.example.sinatext-2.apk Environment.getDataDirectory():/data Environment.getExternalStorageState():mounted Environment.getDownloadCacheDirectory():/cache Environment.getExternalStorageDirectory():/storage/sdcard0 Environment.getRootDirectory():/system
按照路径的特征,我们又可以将文件存储的路径分为两大类,一类是路径中含有包名的,一类是路径中不含有包名的,含有包名的路径,因为和某个App有关,所以对这些文件夹的访问都是调用Context里边的方法,而不含有包名的路径,和某一个App无关,我们可以通过Environment中的方法来访问。
清除数据:类似于恢复出厂设置,删除了所有用户保存的数据。则是指一些固定的用户信息,比如登录信息、进度保存信息等,清理之后,再次运行对应的App,比如微信,则需要重新输入登录信息,而如果是游戏,特别是单机游戏,则就像新游戏一样,之前的进度信息都会被清除而无法继续。即将外部私有数据包(/storage/emulated/0/Android/data/包名)清除,将内部数据下的所有内容(/data/data/包名/XXX)清除;
清除缓存:只是删除了应用软件的缓存资源。手机App应用在运行过程中会产生一些临时数据,比如加载过的页面、填写过的数据等,这些数据的存在有利于对应App无需多次加载而运行加快,这些数据称之为“缓存数据“。清理缓存表示将这些临时数据清除,清除后,对应App再次运行需要重新生成,可能会变慢,但是整体手机运行内存因其释放而增加,反而可能加快。即将外部私有数据下的cache包(/storage/emulated/0/Android/data/包名/cache)清除,将内部数据下的cache包下的内容(/data/data/包名/cache/XXX)清除 。
参考博文
http://blog.csdn.net/summerinnphuket/article/details/50790365
https://www.jianshu.com/p/80e10b3dbba5