Android-存储基础


前言

存储适配系列文章:

在持久化数据的时候,一般都是选择存入到文件里,本篇将着重分析Android 存储相关的知识,也是为Android 10.0 11存储适配打基础。 通过本篇文章,你将了解到:

1、存储划分 2、内部存储 3、外部存储 4、易混淆点说明

1、存储划分

Android 4.4 之前

在Android 4.4 之前,由于硬件发展受限,手机自身的存储空间有限,需要通过外置SD卡来扩展存储空间。

如上图,手机自身的存储空间,称之为机身存储,在Android 4.4 之前作为内部存储使用。当然内部存储空间一般是不够用的,所以需要通过插入外置SD卡来扩充存储空间,这当做外部存储。

Android 4.4之后

在Android 4.4 之后(含),手机机身存储扩大了:

如上图,机身存储划分为两部分:

1、内部存储 2、外部存储

当然,依然可以插入SD卡来扩充存储空间,这部分的存储空间称为扩展的外部存储空间。只是现在机身存储都比较大,很少插入SD卡了。 接下来将以Android 4.4 之后的存储划分来分析具体的存储方案。

2、内部存储

存放位置

回想一下平时使用的持久化方案:

1、SharedPreferences—->适用于存储小文件 2、数据库—->存储结构比较复杂的大文件

以上这些文件都是默认放在内部存储里。 “/” 表示根目录,内部存储里给每个应用按照其包名各自划分了目录,假设App的包名为:com.fish.myapplication 那么该文件在内部存储里的目录为: /data/user/0/com.fish.myapplication/

第一个"/“表示根目录,其后每个”/"表示目录分割符。 “0” 表示是第一个用户,后续添加了多用户则生成相应的用户目录: 如上图,新增了两个用户,生成的目录分别是:“11”、“12”。目前来说,很少开启多用户的。 一般来说,adb shell里是没有权限查看/data目录的。若要查看内部存储,通常是通过Android Studio侧边栏Device File Explorer选择对应的目标设备查看。 同样的,如果包名为:com.fish.myapplication,则对应的内部存储目录为: /data/data/com.fish.myapplication/

/data/user/0/com.fish.myapplication/ 会将值转换到/data/data/com.fish.myapplication/ 路径下。 每个App的内部存储空间仅允许自己访问(除非有更高的权限,如root),程序卸载后,该目录也会被删除。

存储内容

除了SharedPreferences、数据库文件,内部存储还存放了哪些文件呢? 为方便起见,只查看/data/data/目录下的。

刚开始有只有两个空目录。 当进行写入SharedPreferences,创建数据库、写入文件等操作后新增了几个目录:

大致介绍一下以上目录作用:

1、cache–>存放缓存文件 2、code_cache–>存放运行时代码优化等产生的缓存 3、databases–>存放数据库文件 4、files–>存放一般文件 5、shared_prefs–>存放SharedPreferences 文件 6、lib–>存放App依赖的so库 是软链接,指向/data/app/ 某个子目录下

访问方式

既然知道了各类文件存储的目录,那么如何读写这些文件呢? 我们知道在Java 的世界里,操作文件有两种方式:

字符流和字节流

以字节流为为例,一个简单的读取写入文件Demo:

//写入文件
    private void writeFile(String filePath) {
        if (TextUtils.isEmpty(filePath))
            return;

        try {
            File file = new File(filePath);
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
            String writeContent = "hello world
";
            bos.write(writeContent.getBytes());
            bos.flush();
            bos.close();

        } catch (Exception e) {

        }
    }

    //从文件读取
    private void readFile(String filePath) {
        if (TextUtils.isEmpty(filePath))
            return;

        try {
            File file = new File(filePath);
            FileInputStream fileInputStream = new FileInputStream(file);
            BufferedInputStream bis = new BufferedInputStream(fileInputStream);
            byte[] readContent = new byte[1024];
            int readLen = 0;
            while (readLen != -1) {
                readLen = bis.read(readContent, 0, readContent.length);
                if (readLen > 0) {
                    String content = new String(readContent);
                    Log.d("test", "read content:" + content.substring(0, readLen));
                }
            }
            fileInputStream.close();
        } catch (Exception e) {

        }
    }

可以看出,通过FileInputStream/FileOutputStream构造函数传入File对象即可实现文件读写,而File对象的构造依赖于文件的存放路径,因此重点在于如何获取文件的路径。 分别说明各个目录下文件的读写: 1、读写files目录下文件

#Context.java
public abstract File getFilesDir();

使用方式:

private String getFilePath(Context context) {
        //获取files根目录
        File fileDir = context.getFilesDir();
        //获取文件
        File myFile = new File(fileDir, "myFile");
        return myFile.getAbsolutePath();
    }

context.getFilesDir()的结果是返回files目录:

/data/user/0/com.fish.myapplication/files/

拿到对应文件的File对象后,构造相应的输入输出流即可实现对该文件的读写。可以看出,过程虽然简单但是有点

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/292606.html

(0)
上一篇 2022年11月4日 23:31
下一篇 2022年11月4日 23:32

相关推荐

发表回复

登录后才能评论