当前位置: 首页 > backend >正文

【Android】内外部存储的读写

在这里插入图片描述
三三要成为安卓糕手

一:安卓中文件存储位置

  • 应用内部存储空间目录:这些目录既包括用于存储持久性文件的专属位置,也包括用于存储缓存数据的其他位置。系统会阻止其他应用访问这些位置,并且在 Android 10(API 级别 29)及更高版本中,系统会对这些位置进行加密。这些特征使得这些位置非常适合存储只有应用本身才能访问的敏感数据。
  • 应用专属外部存储:这些目录既包括用于存储持久性文件的专属位置,也包括用于存储缓存数据的其他位置。其他应用可以在具有适当权限的情况下访问这些目录,更多的还是自己使用。当应用被卸载时,存储在这里的文件会被删除。
  • 公共存储空间:如果明确打算创建其他应用能够访问的文件,可以将文件存储在外部存储空间的共享存储空间部分所有应用均可访问,适合存储对所有应用可见的数据,如图片、音乐、视频等

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

二:应用内部私有存储数据的写入

internal 内部的

external 外部的

1:客户端布局

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".file.PrivateFileActivity"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="应用内部私有存储相关操作"android:textSize="30sp" /><Buttonandroid:id="@+id/btn_internal_save"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="20dp"android:text="保存文件" /><Buttonandroid:id="@+id/btn_internal_read"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="读取文件" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="30dp"android:text="应用外部私有存储相关操作"android:textSize="30sp" /><Buttonandroid:id="@+id/btn_external_save"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="20dp"android:text="保存文件" /><Buttonandroid:id="@+id/btn_external_read"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="读取文件" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="20dp"android:text="=============我是分割线==========="android:textSize="20sp" /><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="我想把这段内容保存到文件当中"android:textSize="20sp" /><EditTextandroid:id="@+id/et_info"android:layout_width="match_parent"android:layout_height="wrap_content" /><TextViewandroid:id="@+id/tv_info"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="10dp"android:text="读取到了如下信息:\n" /></LinearLayout>

2:数据写入文件代码

        findViewById(R.id.btn_internal_save).setOnClickListener(view -> {new Thread() {@Overridepublic void run() {super.run();File file = new File(getFilesDir(), "content.txt");Log.i(TAG, "run: absolutePath: " + file.getAbsolutePath());try (FileOutputStream fos = new FileOutputStream(file);//缓冲输出流BufferedOutputStream bos = new BufferedOutputStream(fos)) {//获取框中的数据String content = etInfo.getText().toString().trim();byte[] bytes = content.getBytes();bos.write(bytes, 0, bytes.length);} catch (FileNotFoundException e) {throw new RuntimeException(e);} catch (IOException e) {throw new RuntimeException(e);}}}.start();});
  • getFilesDir():返回内部存储位置的目录 ; "context.txt"给即将创建的文件取得名字
  • 资源自动关闭:传统方式在 try 块中创建流,需要在 finally 块中显式调用 close() 手动释放资源;这里直接放到try()括号中,操作完毕会自动关闭资源;(流操作实现了 AutoCloseable 接口)
  • 缓冲输出流:遇到大文件,不会很吃力;攒一波数据一次性写入,减少读写次数,提高效率;内部本身自带一个字节数组,这里我们自己申请了一个;资源自动close() 前内部会先调用 flush(),保证缓冲区中剩余的所有数据(可能缓冲区没攒满一波也能)写入到底层输出流
  • bos.write():传入有数据的数组,从offset到末尾所有的数据写入到文件中
  • 读文件是一个耗时的操作,放在子线程中

3:如何理解输入和输出流

理清楚程序(也就是代码)和文件之间的流向就能区分开

  • “从文件里读取内容,放到程序里”,数据流向是:文件 → 程序 那就是输入流InputStream 相关类)
  • “把代码中的数据(比如说输入框EditText中的内容),存储到文件里” 数据的流向:程序 → 文件 那就是输出流OutputStream 相关类)

4:如何理解字节和字符

程序这边就是字符,存储一方就是字节;所以输出流操作时,往往先要把字符数据转换为字节格式,在写入保存到文件中

上面代码中的流程:字符串(字符)→ 字节数组 → 字节流写入文件

  • 程序里操作的是输入框中的字符内容(String 类型)。
  • 当要写入文件时,通过 content.getBytes() 把字符转换为字节,然后用字节流(FileOutputStreamBufferedOutputStream)将字节写入文件存储。

5:如何理解缓冲流

BufferedOutputStream缓冲流: 是先将数据暂存在内存缓冲区中,当缓冲区满了自动或手动调用 flush()/close() 时,才会将数据真正写入底层的 FileOutputStream(即磁盘文件)

6:效果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

三:应用内部私有存储数据的读取

findViewById(R.id.btn_internal_read).setOnClickListener(view -> {new Thread(new Runnable() {@Overridepublic void run() {//拿到这个文件对象File file = new File(getFilesDir(), "content.txt");//FileInputStream本身读取的是字节,转化成读字符try (FileInputStream fis = new FileInputStream(file);InputStreamReader isr = new InputStreamReader(fis);//字节流转化为字符流BufferedReader br = new BufferedReader(isr)//缓冲读取) {StringBuffer buffer = new StringBuffer();String line;while((line = br.readLine()) != null){buffer.append(line);}String result = buffer.toString().trim();tvInfo.setText(tvInfo.getText() + result);} catch (FileNotFoundException e) {throw new RuntimeException(e);} catch (IOException e) {throw new RuntimeException(e);}}}).start();});

1:字节转换字符

通过 InputStreamReader 把字节流转为字符流,再用 BufferedReader 包装,readLine读取

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2:效果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

四:应用外部私有存储数据的写入

        findViewById(R.id.btn_external_save).setOnClickListener(view -> {String state = Environment.getExternalStorageState();Log.i(TAG, "onCreate: 外部存储状态"+" "+ state);if (Environment.MEDIA_MOUNTED.equals(state)){//既可读又可写File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), "content.txt");String path = file.getAbsolutePath();Log.i(TAG, "onCreate: 文件的路径是" + path);//把字符流转化为字节流,从程序写到硬盘中try (FileOutputStream fos = new FileOutputStream(file);BufferedOutputStream bos = new BufferedOutputStream(fos)){String text = etInfo.getText().toString().trim();byte[] bytes = text.getBytes();bos.write(bytes,0,bytes.length);} catch (FileNotFoundException e) {throw new RuntimeException(e);} catch (IOException e) {throw new RuntimeException(e);}} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {//只读}else{//外部存储不可用}});

1:获取外部文件路径

  • getExternalFilesDir():返回外部私有目录
  • Environment.DIRECTORY_DOCUMENTS:DOCUMENTS指的就是下图中的文件夹,可能还会有Picture文件夹对应的就是PICTURE;这是内部封装好的常量值,当然也可以直接传入字符串

2:外部文件读写权限

  • Environment.getExternalStorageState(); 获取外部存储状态
  • Environment.MEDIA_MOUNTED 既可读又可写
  • Environment.MEDIA_MOUNTED_READ_ONLY 只能读取
  • Environment.MEDIA_UNMOUNTED 未挂载

3:挂载的概念

media媒体 mounted已挂载

简单说,“挂载” 就是给存储设备(比如 U 盘、SD 卡)在系统里 “办个接入手续”,让系统能找到它、用它。

比如插 U 盘到电脑,系统弹出 U 盘图标,就是完成了挂载;安卓手机识别到 SD 卡能存照片,也是 SD 卡挂载成功了。

4:效果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

五:应用外部私有存储数据的读取

        findViewById(R.id.btn_external_read).setOnClickListener(view -> {String state = Environment.getExternalStorageState();if (Environment.MEDIA_MOUNTED.equals(state)){File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), "content.txt");try(FileInputStream fis = new FileInputStream(file);InputStreamReader isr = new InputStreamReader(fis);BufferedReader reader = new BufferedReader(isr)){StringBuffer buffer = new StringBuffer();String line;while((line = reader.readLine()) != null){buffer.append(line);}String result = buffer.toString();Log.i(TAG, "onCreate: result " + result);tvInfo.setText(tvInfo.getText() + result);} catch (FileNotFoundException e) {throw new RuntimeException(e);} catch (IOException e) {throw new RuntimeException(e);}}});

4.0~6.0低版本的安卓,都可以用上述方法对内部存储文件进行处理;高版本的安卓,对处理文件的权限要求越发的严格,就要使用一些更新的方式去访问外部存储权限,

http://www.xdnf.cn/news/20399.html

相关文章:

  • C++-类型转换
  • macos安装openjdk17
  • zotero扩容
  • 【Leetcode100】算法模板之二叉树
  • 【机器学习】通过tensorflow搭建神经网络进行气温预测
  • Ubuntu系统下Python连接国产KingbaseES数据库实现增删改查
  • 计算机视觉(十二):人工智能、机器学习与深度学习
  • 03-Redis 安装指南:从版本选择到多系统部署(Windows+macOS+Linux)
  • 【机器学习】综合实训(一)
  • AI工具深度测评与选型指南 - 音视频生成与处理类
  • Kotlin 协程之 突破 Flow 限制:Channel 与 Flow 的结合之道
  • 如何终止画图
  • 海尔电视刷机
  • 【算法】92.反转链表Ⅱ--通俗讲解
  • More Effective C++ 条款32:在未来时态下发展程序
  • 带fat32文件系统的bin二进制文件制作教程
  • 【FastDDS】XTypes Extensions
  • 没有深度学习
  • 笔记:ubuntu安装matlab
  • 机械硬盘的工作原理
  • 接口权限验证有哪些方式
  • B.50.10.08-Nacos架构与电商应用
  • 容器镜像:运行容器的静态蓝图
  • 基于SpringBoot+JSP开发的潮鞋网络商城
  • ISO/IEC 27001 第八章 运行
  • MIMO-OFDM ISAC Waveform Design for Range-Doppler Sidelobe Suppression
  • 【C++ 双指针技巧】
  • 嵌入式学习笔记--Linux系统编程阶段--DAY06进程间通信-消息队列
  • Linux知识回顾总结----文件系统
  • 南科大适应、协同与规划的完美融合!P³:迈向多功能的具身智能体