欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

总结系列-Android文件存储相关

程序员文章站 2022-04-14 11:22:33
Android开发中有五种数据持久化API:内部存储目录:/data/data/特点:每个应用独占一个以包名命名的私有文件夹在应用卸载时被删除对MediaScanner不可见内部存储位于系统中很特殊的一个位置,对于设备中每一个安装的 App,系统都会在data/data/packagenam......
总结系列-Android文件存储相关
 

Android开发中有五种数据持久化API:

总结系列-Android文件存储相关
内部存储
 
  • 目录:/data/data/
  • 特点:
    • 每个应用独占一个以包名命名的私有文件夹
    • 在应用卸载时被删除
    • 对MediaScanner不可见
 
内部存储位于系统中很特殊的一个位置,对于设备中每一个安装的 App,系统都会在 data/data/packagename/xxx 自动创建与之对应的文件夹
 
Android可以说是一个Linux操作系统,它的内部存储空间对于应用程序和用户来讲就是“/data/data“目录。内部存储与外部存储相比有着比较稳定,存储方便,操作简单,更加安全(可以控制访问权限)等优点,而它唯一的缺点就是空间有限。
总结系列-Android文件存储相关
 
对于内部存储路径,我们一般通过以下两种方式获取,内部存储空间的获取都需要使用Context:

context.getFileDir()

对应内部存储的路径为: data/data/packagename/files,但是对于有的手机如:华为,小米等获取到的路径为:data/user/0/packagename/files

context.getCacheDir()

对应内部存储的路径为: data/data/packagename/cache,但是对于有的手机如:华为,小米等获取到的路径为:data/user/0/packagename/cache
总结系列-Android文件存储相关
外部存储
外部存储即storage文件夹或mnt文件夹。需要注意的是storage中有一个sdcard0文件夹,其中又分为公有目录和私有目录:
公有目录:有9大类,比如DCIM、Download等系统为用户创建的文件夹;
私有目录: 即Android文件夹/storage/sdcard/Android/,其中的data文件夹包含了许多包名组成的文件夹。
 
  • 私有目录(private):storage/emulated/0/Android/
    • 特点
      • 每个应用独占以包名命名的私有文件夹
      • 在应用卸载时被删除
      • 对MediaScanner不可见(例外:多媒体文件夹 API 21)
    • 适用场景:非私密数据,需要随应用卸载删除
  • 公共目录(public):外部存储中除了私有目录外的其他空间
    • 特点
      • 所有应用共享
      • 在应用卸载时不会被删除
      • 对MediaScanner可见
    • 适用场景:非私密数据,不需要随应用卸载删除
 
总结系列-Android文件存储相关

getExternalCacheDir()

对应外部存储路径:/storage/emulated/0/Android/data/packagename/cache

getExternalFilesDir(String type)

对应外部存储路径:/storage/emulated/0/Android/data/packagename/files
 
其他:
1、Environment.getDataDirectory() = /data
这个方法是获取内部存储的根路径
 
2、getFilesDir().getAbsolutePath() 
= /data/user/0/packname/files
这个方法是获取某个应用在内部存储中的files路径
 
3、getCacheDir().getAbsolutePath() 
= /data/user/0/packname/cache
这个方法是获取某个应用在内部存储中的cache路径
 
4、getDir(“myFile”, MODE_PRIVATE).getAbsolutePath() 
= /data/user/0/packname/app_myFile
这个方法是获取某个应用在内部存储中的自定义路径
 
5、Environment.getExternalStorageDirectory().getAbsolutePath() 
= /storage/emulated/0
这个方法是获取外部存储的根路径
 
6、Environment.getExternalStoragePublicDirectory (Environment.DIRECTORY_DCIM)
 = /storage/emulated/0
这个方法是获取外部存储公有目录
 
7、getExternalFilesDir(“”).getAbsolutePath() 
= /storage/emulated/0/Android/data/packname/files
这个方法是获取某个应用在外部存储中的files路径
 
8、getExternalCacheDir().getAbsolutePath() 
= /storage/emulated/0/Android/data/packname/cache
这个方法是获取某个应用在外部存储中的cache路径
 
总结系列-Android文件存储相关
因为外部存储不一定可用,所以返回值可为空或空数组
区分外部存储与SD卡存储
 
File[] files;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    files = getExternalFilesDirs(Environment.MEDIA_MOUNTED);
    for(File file:files){
        Log.e("main",file);
    }
}
结果:
/storage/emulated/0/Android/data/packname/files/mounted
/storage/B3E4-1711/Android/data/packname/files/mounted
内部存储我们尽量不要去使用。但是当手机没有外部存储时,我们还是得使用内部存储,检测外部存储是否可用
public static String getFilePath(Context context,String dir) {
    String directoryPath="";
    if (MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ) {//判断外部存储是否可用
        directoryPath =context.getExternalFilesDir(dir).getAbsolutePath();
        }else{//没外部存储就使用内部存储  
        directoryPath=context.getFilesDir()+File.separator+dir;
        }
        File file = new File(directoryPath);
        if(!file.exists()){//判断文件目录是否存在
        file.mkdirs();
        }
    return directoryPath;
}
 
 外部存储并不总是可用的,因为外部存储可以移除(早期设备)或者作为USB存储设备连接到PC,
访问前必须检查是否挂载(mounted):
 
//检测是否可用: 
boolean mExternalStorageAvailable = false;
boolean mExternalStorageWriteable = false;/* 检查外部存储是否可读写 */void updateExternalStorageState() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
            // 可读写
        mExternalStorageAvailable = mExternalStorageWriteable = true;
    } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
            // 可读
        mExternalStorageAvailable = true;
        mExternalStorageWriteable = false;
    } else {
        mExternalStorageAvailable = mExternalStorageWriteable = false;
    }}
 
或者:
String externalStorageState = Environment.getExternalStorageState();
if (externalStorageState.equals(Environment.MEDIA_MOUNTED)){
  //sd卡已经安装,可以进行相关文件操作
}
//监听外部存储状态
BroadcastReceiver mExternalStorageReceiver;/* 开始监听 */void startWatchingExternalStorage() {
    mExternalStorageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
                // 更新状态
            updateExternalStorageState();
        }
    };
    IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
    filter.addAction(Intent.ACTION_MEDIA_REMOVED);
    // 动态注册广播接收器
    registerReceiver(mExternalStorageReceiver, filter);
    updateExternalStorageState();}/* 停止监听 */void stopWatchingExternalStorage() {
        // 注销广播接收器
    unregisterReceiver(mExternalStorageReceiver);}
 
 
Environment.getExternalStorageState()状态:
MEDIA_UNKNOWN SD卡未知
MEDIA_REMOVED SD卡移除
MEDIA_UNMOUNTED SD卡未安装
MEDIA_CHECKING SD卡检查中,刚装上SD卡时
MEDIA_NOFS SD卡为空白或正在使用不受支持的文件系统
MEDIA_MOUNTED SD卡安装
MEDIA_MOUNTED_READ_ONLY SD卡安装但是只读
MEDIA_SHARED SD卡共享
MEDIA_BAD_REMOVAL SD卡移除错误
MEDIA_UNMOUNTABLE 存在SD卡但是不能挂载,例如发生在介质损坏
 

/storage/sdcard,/sdcard,/mnt/sdcard,/storage/emulated/0之间的关系

在真机上,getExternalStorageDirectory()获取到的路径如下表所示:
系统版本    结果  (注意:下面路径中的文件夹相同)
4.0    /mnt/sdcard
4.1    /storage/sdcard0
4.2    /storage/sdcard0
4.4    /storage/emulated/0
6.0    /storage/emulated/0
其中sdcard/、mnt/sdcard、storage/sdcard0、storage/emulated/0、storage/emulated/legacy都是同一个路径的不同”指针“,指向的是同一个地方,只是不同Android版本的叫法不一样。
 
在Android版本4.2JellyBean之前,获取sdcard的路径是/sdcard/,但在JellyBean版本之后的路径成为了/sdcard/0,或者是/sdcard/legacy(legacy可以是0、1、2……),这个“0”到底代表着什么含义?
这是从JellyBean版本起的一个新特征——多用户。因此为了处理单独的账户,部分目录结构必须被改变,/sdcard/legacy始终指向当前登录的用户的SD卡目录。
 
正因“多用户”功能的增加,内外部存储发生了以下变化:
内部存储: 原先的/data/data/其实相当于直接链接到当前用户文件夹的,变成了/data/user/0/。
外部存储:例如sd卡路径不再是/sdcard/,而是/sdcard/legacy/(legacy可以是0、1、2……),其中的“0”可以当成“设备拥有者”,或者称为“第一用户”(“第一用户”毫无疑问的是“设备所有者”,只有此用户才能创建额外账户)。
 
 
 
 
 

参考:
 
 

本文地址:https://blog.csdn.net/u011200604/article/details/107959231