Android存储之分区存储适配

本文详细介绍了Android系统内部存储与外部存储的概念,以及Android10与Android11版本中分区存储的适配方法。阐述了如何在不同Android版本间进行存储操作,包括获取存储路径、文件操作API及权限申请。

一.Android存储分区介绍

1.简介

Android 存储分为内部存储(Internal storage)和外部存储(External storage)。有许多用户认为外部存储意味着SD存储卡或外部硬盘,这是完全错误的认识。

2.内部存储

内部存储是用于存储Android系统本身和应用程序的存储区域,Android设备中的Android系统和应用程序都是存在该内部存储区,例如手机的/system/目录、/data/等目录。 如果没有这一块存储区域是无法运行Android系统和应用程序的。其中data/data/包名/目录是Android系统提供给应用存储数据的内部存储空间,由应用程序创建的SharedPreferences、Sqlite数据库、缓存文件等目录都是保存在该文件夹中。该目录只能由该应用程序自身访问,其他应用程序和用户无法访问存储在此空间中的文件,并且该目录会随着的应用的卸载而被移除。

//获取手机内部存储空间的绝对路径:/data
Environment.getDataDirectory().getAbsolutePath();

需要注意的一点是如果Android设备被获取到了最高权限(ROOT)那么是可以访问内部存储空间中的文件数据的!

2.外部存储

手机的内部存储空间通常不会很大,一旦手机的内部存储容量被用完, 可能会出现手机无法使用的情形。因此我们需要将一些比较大的媒体文件放置到机身外部存储中。在早先的手机中是具备一个SD存储卡槽的,插入SD存储卡,系统会将Sd储存卡的存储空间挂载成外部存储空间。不过现在大部分手机已经取消支持SD存储卡扩展功能了。取而代之的是手机会自带一个机身内置存储空间,这个机身存储和SD存储卡的功能是完全一样的,Android系统会将内置存储空间的一部分区域划分为内部存储,另一部分划分为外部存储空间,然后通过 Linux 文件挂载的方式将这些存储空间进行挂载。

//获取手机外部存储的路径:/storage/emulated/0
Environment.getExternalStorageDirectory().getAbsolutePath();

3.内部存储和外部存储的区别

上文中讲到在以前的安卓手机中内置存储(机身存储)就是内部存储,外部存储就是扩展的SD卡。但目前很多的中高端机器的自带的内置存储都是很大的储存空间了, 因此Android4.4系统及以上的手机将机身内置存储分为了”内部存储internal” 和”外部存储external”两个不同的储存区域,用来存储不同的数据。如果Android4.4系统及以上的手机还支持单独外接SD卡,那么外接的SD卡一定是外部存储。此时手机上是有两个外部存储空间的。那么如何去区分这两个外部存储?google官方给我们提供了getExternalFilesDirs这样一个API来获取多个外部存储空间, 它返回一个File数组,File数组中就包含了手机自身所带的外部存储和外接SD卡所定义的外部存储了。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    File[] files = getExternalFilesDirs(Environment.MEDIA_MOUNTED);
    for(File file:files){
        Log.e("Environment", file.getAbsolutePath())
    }

注意:Android手机是支持外接多个外部存储介质空间的,如果用户在设备上移除了介质,则外部存储可能变为不可用状态。 所以在使用外部存储执行任何工作之前, 最好调用 getExternalStorageState() 以检查介质是否可用。

//判断外部存储是否可用
if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
    ...
}


对于Android开发者来说只和外部存储和内部存储打交道,Android提供的开发接口也只是获取内部存储和外部存储的目录地址。而对开发者屏蔽了内置存储卡和外置SD卡相关操作。

结论内部存储和外部存储可以是在同一块存储介质上面的,只是概念上做了区分,内部存储和外部存储是一块存储介质上的不同区域。

二.Android应用存储目录

1.内部存储空间中的应用私有目录

对于设备中每一个安装的 App,系统都会在内部存储空间的 data/data 目录下以应用包名为名字自动创建与之对应的文件夹。这个文件夹包含了SharedPreferences 和 SQLiteDatabase 持久化应用相关数据等。该文件夹是应用的私有文件夹,其他应用(和用户)不能访问文件夹里面的内容的(Root用户除外)。每个应用访问自己的内部存储是不需要权限的。 当用户卸载该应用时,这些文件也会被移除。
Android SDK 提供有如下方法可以获取并操作内部存储空间下应用私有目录文件的方法,都位于 Application Context 中,供开发者直接调用:

  • 获取当前应用包名文件夹下的files文件夹路径:

    context.getFilesDir().getAbsolutePath();
    

    返回结果:data/data/packagename/files

  • 获取当前应用包名文件夹下cache文件夹路径:

    context.getCacheDir().getAbsolutePath();
    

    返回结果:data/data/packagename/cache

  • 在内部存储空间内创建(或打开现有的)目录:

    context.getDir("setting", MODE_PRIVATE).getAbsolutePath();
    

    返回结果:data/data/packagename/setting

  • 获取内部存储files路径下的所有文件名:

    context.fileList();
    
  • 删除内部存储files路径下的文件:

    //返回true则表示删除成功
    context.deleteFile(filename);
    

要在files或者cache其中一个目录中创建新文件,可以使用File()构造函数,传递给File上述方法提供的指定内部存储目录的方法:

//保存内容到私有的files目录
public void save(String filename, String content)throws IOException{
    File file= new File(context.getFilesDir(), filename);
    FileOutputStream myfos= new  FileOutputStream(file);
    myfos.write(content.getBytes());
    myfos.close();
}

或者是读取文件:

//通过文件名来获取私有的files目录中的文件
public String get(String filename) throws IOException {
    File file= new File(context.getFilesDir(), filename);
    FileInputStream fis = new FileInputStream(file);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] data = new byte[1024];
    int len = -1;
    while ((len = fis.read(data)) != -1) {
        baos.write(data, 0, len);
    }
    return new String(baos.toByteArray());
}

并且Android系统可以调用Context类中提供了一个openFileOutput()方法,以获取FileOutputStream来对文件进行操作。 openFileOutput()方法接受两个参数:

  • 第一个参数是文件名,在文本创建的时候使用的就是这个名称,注意这里指定的文件名不可以包含路径(因为默认存储到/data/data//files/目录下)。
  • 第二个参数是文件的操作模式,主要有两种:
    1. MODE_PRIVATE:默认的操作模式,表示当指定同样文件名的时候,当该文件名有内容时,再次调用会覆盖原内容。
    2. MODE_APPEND:表示该文件如果已存在就往文件里面追加内容。

调用 openFileOutput() 来获取 FileOutputStream,得到这个对象后就可以

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值