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 大容量存储以传输文件后,可由用户修改这些文件。

外部存储就是文件系统目录中看到的storage文件夹,也有可能是mnt文件夹,在storage文件夹中有一个sdcard文件夹,这个文件夹中的文件又分为两类,一类是公有目录,还有一类是私有目录,比如DCIM,Download等这些系统为我们创建的文件夹,私有目录就是android这个文件夹,这个文件夹打开后里边有一个data文件夹,打开这个文件夹,里面包含了许多包名组成的文件夹。
1)读取状态
要读取或写入外部存储上的文件,应用必须获取READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE系统权限。
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();
2)公共目录:

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)其他目录

  1. /cache 目录
    通过 API Environment.getDownloadCacheDirectory() 访问,存储下载文件的缓存路径
  2. /system 目录
    通过 API Environment.getRootDirectory() 访问,该目录下也有一个 app 目录,存放的是系统应用的 apk 文件。
/system/app 和 /data/app 的区别
  • /data/app 里软件权限没全开,/system/app 里的软件获取了所有权限
  • /data/app 可以应用卸载,/system/app 只能 root 后删除
  • /data/app 文件夹大小随便,/system/app 文件夹有大小限制
  • 卸载/system/app 目录下的文件并不会增加系统空间,即可用 ROM 空间
  1. /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



posted @ 2017-12-27 14:40  jingmengxintang  阅读(1973)  评论(0编辑  收藏  举报