Android插件化(四)基础之文件存储
Android插件化(四)基础之文件存储
android文件存储解析
安卓中提供了Context中的方法与Environment类来操作文件。
Context文件操作方法
public File getFileStreamPath(String name)
public String[] fileList()
public File getFilesDir()
public File getNoBackupFilesDir()
public File getExternalFilesDir(String type)
public File[] getExternalFilesDirs(String type)
public File getObbDir()
public File[] getObbDirs()
public File getCacheDir()
public File getCodeCacheDir()
public File getExternalCacheDir()
public File[] getExternalCacheDirs()
public File[] getExternalMediaDirs()
public File getDir(String name, int mode)
用Log把它们都显示出来
Log.d("context", "context.getFileStreamPath-->" +this.getFileStreamPath("test").toString());
Log.d("context", "context.getDir-->" +this.getDir("test", Context.MODE_PRIVATE).toString());
Log.d("context", "context.getFilesDir-->" +this.getFilesDir().toString());
Log.d("context", "context.getNoBackupFilesDir" +this.getNoBackupFilesDir().toString());
Log.d("context", "context.getCacheDir-->" +this.getCacheDir().toString());
Log.d("context", "context.getCodeCacheDir" +this.getCodeCacheDir().toString());
Log.d("context", "context.getDatabasePath-->" +this.getDatabasePath("test").toString());
Log.d("context", "context.getObbDir-->" +this.getObbDir().toString());File[] files1 = this.getObbDirs();
for (File file : files1) {Log.d("context", "context.getObbDirs-->" + file.toString());
}
File[] files2 = this.getExternalMediaDirs();
for (File file : files2) {Log.d("context", "context.getExternalMediaDirs" + file.toString());
}Log.d("context", "context.getExternalCacheDir-->" + this.getExternalCacheDir().toString());
File[] files3 = this.getExternalCacheDirs();
for (File file : files3) {Log.d("context", "context.getExternalCacheDirs-->" + file.toString());
}Log.d("context", "context.getExternalFilesDir-->" + this.getExternalFilesDir(Environment.DIRECTORY_ALARMS).toString());File[] files4 = this.getExternalFilesDirs(Environment.DIRECTORY_ALARMS);
for (File file : files4) {Log.d("context", "context.getExternalFilesDirs-->" + file.toString());
}
og输出结果(不同版本的安卓系统,目录可能也不相同):
context.getFileStreamPath-->/data/data/cn.hufeifei.environmenttest/files/test
context.getDir-->/data/data/cn.hufeifei.environmenttest/app_test
context.getFilesDir-->/data/data/cn.hufeifei.environmenttest/files
context.getNoBackupFilesDir/data/data/cn.hufeifei.environmenttest/no_backup
context.getCacheDir-->/data/data/cn.hufeifei.environmenttest/cache
context.getCodeCacheDir/data/data/cn.hufeifei.environmenttest/code_cache
context.getDatabasePath-->/data/data/cn.hufeifei.environmenttest/databases/test
context.getObbDir-->/storage/emulated/0/Android/obb/cn.hufeifei.environmenttest
context.getObbDirs-->/storage/emulated/0/Android/obb/cn.hufeifei.environmenttest
context.getExternalMediaDirs/storage/emulated/0/Android/media/cn.hufeifei.environmenttest
context.getExternalCacheDir-->/storage/emulated/0/Android/data/cn.hufeifei.environmenttest/cache
context.getExternalCacheDirs-->/storage/emulated/0/Android/data/cn.hufeifei.environmenttest/cache
context.getExternalFilesDir-->/storage/emulated/0/Android/data/cn.hufeifei.environmenttest/files/Alarms
context.getExternalFilesDirs-->/storage/emulated/0/Android/data/cn.hufeifei.environmenttest/files/Alarms
Environment工具类中提供了以下几个方法:
Environment.getDataDirectory();
Environment.getRootDirectory();
Environment.getDownloadCacheDirectory();
Environment.getExternalStoragePublicDirectory(String type);
Environment.getExternalStorageDirectory();
Environment.getExternalStorageState();
Environment.getExternalStorageState(File path)
Environment.getStorageState();//已被getExternalStorageState取代
1.前三个方法
用Log输出来:
//IS标识内部存储
Log.d("Environment-IS", Environment.getDataDirectory().toString());
Log.d("Environment-IS", Environment.getDownloadCacheDirectory().toString());
Log.d("Environment-IS", Environment.getRootDirectory().toString());
输出结果为:
D/Environment-IS: /data
D/Environment-IS: /cache
D/Environment-IS: /system
2.getExternalStoragePublicDirectory方法
getExternalStoragePublicDirectory方法用来获取安卓外部存储中系统应用经常用到的公共文件夹,
在Environment中定义了这些文件夹的名字:
Environment.DIRECTORY_MUSIC = "Music"
Environment.DIRECTORY_PODCASTS = "Podcasts"
Environment.DIRECTORY_RINGTONES = "Ringtones"
Environment.DIRECTORY_ALARMS = "Alarms"
Environment.DIRECTORY_NOTIFICATIONS = "Notifications"
Environment.DIRECTORY_PICTURES = "Pictures"
Environment.DIRECTORY_MOVIES = "Movies"
Environment.DIRECTORY_DOWNLOADS = "Download"
Environment.DIRECTORY_DCIM = "DCIM"
Environment.DIRECTORY_DOCUMENTS = "Documents"
它们的目录一般在/storage/emulated/0/<dir_name> (dir_name就是Environment中定义的这些字符串常量)
3.最后的三个方法
最后面三个方法是用来获取挂载点的状态(在Linux中把一些特殊目录称为所谓的挂载点,有点类似于Windows中的分区):
Environment.MEDIA_REMOVED;//媒体存储已经移除了
Environment.MEDIA_UNMOUNTED;//存储媒体没有挂载
Environment.MEDIA_CHECKING;//正在检查存储媒体
Environment.MEDIA_NOFS;//存储媒体是空白或是不支持的文件系统no_file_system
Environment.MEDIA_MOUNTED;//存储媒体已经挂载,并且挂载点可读/写
Environment.MEDIA_MOUNTED_READ_ONLY;//存储媒体已经挂载,挂载点只读
Environment.MEDIA_SHARED;//存储媒体正在通过USB共享
Environment.MEDIA_BAD_REMOVAL;//在没有挂载前存储媒体已经被移除
Environment.MEDIA_UNMOUNTABLE;//存储媒体无法挂载,可能是文件系统损坏了
Environment.MEDIA_EJECTING;//存储媒体正在移除
Environment.MEDIA_UNKNOWN;//未知的存储状态
下面图片大概地概括了上面的方法
总结:
- Context中的方法或得到的路径都与应用包名相关*
- Environment中的方法与整个系统有关*
/storage/sdcard0
, /sdcard
, /mnt/sdcard
,/storage/emulated/legacy
的区别
关于android的4.2的0文件夹的详解
android 4.0
在galaxy nexus(GN)手机上userdata分区很大,被挂在/data目录,用户的数据通常是放在sd卡上,然而gn是没有sd卡的,所以google想了一个办法,就是虚拟一个。
所以,在userdata分区下有个目录叫media,是内置sd卡的数据存储位置,使用fuse技术将/data/media
虚拟成为一个叫做/dev/fuse
的设备,为了让程序能认出来,被同时挂载在 /mnt/sdcard
目录,
又为了兼容以前的程序,做了一个快捷方式(linux系统里叫软连接) /sdcard
指向的是 /mnt/sdcard
.
当然,这些都是4.0的做法。
android 4.1
在4.1里,同样也会使用fuse技术,/dev/fuse
会被同时挂载到/storage/sdcard0
目录,这个sdcard0表示第一个sd卡(如果有外置sd卡,那会多一个 /storage/sdcard1
,比如我的xoom), /sdcard
软连接会指向 /storage/sdcard0
,此时/mnt/sdcard
也是个软连接,会指向/storage/sdcard0
。
如果你通过otg线接U盘,会被挂载到 /storage/usb0
目录,stickmount这个软件为了让图库、快图、mx player等软件,能看到u盘里的数据,又同时挂载到 /storage/sdcard0/usStorage/sda1
.
也许你会问,为什么不是usb0,而是sda1,这是linux的对硬盘的命名方式,如果你的u盘有多个分区,就分别是sda1,sda2这样一直排下去了。
android 4.2
谷歌是不是没事干啊,非要给android搞个多用户,你想想啊,在中国,可能因为经济问题,家里不是每人一个电脑,在美国,几乎需要用电脑的人,都会自己有一台或多台,一台电脑多人用的情况少之又少,这就是为什么叫PC了,顾名思义,个人电脑。像手机和平板这些东西,更加私人化了,很少公用了吧,我想在中国也是如此吧。
当然,谷歌也不完全是抽风,因为他有更大的战略部署,而且平板也的确有多人用的可能。
所以谷歌搞出来一个多用户,那每个人的应用、数据、个性配置都要分开吧。 应用和个性配置好弄,想想啊,通过权限控制,每人只能看自己的应用就行了,桌面也可以用自己的。
那数据怎么办????
好吧,调整用户数据的挂载结构。android 4.2,同样也会使用fuse技术/dev/fuse 会被挂载到/storage/emulated/0
目录,为什么是0呢,你还记得上边的sdcard0吧,第一个的意思。(如果有第二个,应该就是/storage/emulated/1
,我们的三儿子没有外置sd卡,所以没法验证)
为了兼容以前,同时挂载到 /storage/emulated/legacy
(故名思议,传统的),还建立三个软连接 /storage/sdcard0
,/sdcard
,/mnt/sdcard
,都指向 /storage/emulated/legacy
还有值得一提的是,4.2刚出来,这块变动又比较大,所以stickmount要升级到2.2之后,才可以通过otg挂载u盘了。
也许你会问,这个0和多用户有什么关系呢,那是因为多用户这个新特性,只在平板上才启用,在手机上会被禁用的。但是底层实现是一致的。 /mnt/shell/emulated
目录和 /storage/emulated
下的文件夹是一样的。(注意,这个/mnt/shell/emulated
不是挂载出来的)
/mnt/shell/
是为了多用户准备的,因为linux的多用户是基于shell实现的。
4.2在平板上的多用户
我前一段时间给XOOM Wifi刷上了CM10.1的4.2.1,成功开启多用户特性。新建的用户id从10开始。
- 默认用户的sdcard目录:
/storage/emulated/0
- 新建的第一个用户的sdcard目录:
/storage/emulated/10
- 新建的第二个用户的sdcard目录:
/storage/emulated/11