Android入门第50天-读写本地文件

news2024/11/24 19:39:44

简介

为了这个系列,我的代码已经准备到了第150天了。接下来的内容会越来越精彩,我们也越来越开始进入Android的一些高级功能上的编程了。今天我们就要讲Android中对本地文件进行读写的全过程。

课程目标

  1. 输入文件名、输入文件内容后按【保存到SD卡】,可以把文件保存到SD卡根目录;
  2. 输入文件名,按【读取SD卡中的文件】,可以根据输入的文件名把文件内容显示成Toast;
  3. 搞清Android中对于SD卡读写时所需要的静态权限申请、动态权限申请;

以上一共我们有3个目标,根据目标下面开始教程。

UI端

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="清输入文件名" />

    <EditText
        android:id="@+id/editFileName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="文件名" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="清输入文件内容" />

    <EditText
        android:id="@+id/editFileContents"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="文件内容" />

    <Button
        android:id="@+id/buttonSave"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="保存到SD卡" />

    <Button
        android:id="@+id/buttonClean"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="清空" />

    <Button
        android:id="@+id/buttonRead"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="读取sd卡中的文件" />

</LinearLayout>

 我们的UI端很简单,用LinearLayout从上到下依次把一系列元素都设置好。接着我们来看我们的后端代码。

静态授权-AndroidManifest.xml文件内容

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <!-- 在SDCard中创建与删除文件权限 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
        tools:ignore="ProtectedPermissions" />
    <!-- 往SDCard写入数据权限 -->
    <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
        tools:ignore="ScopedStorage" />
    <!--外部存储的写权限-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <!--外部存储的读权限-->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <application
        android:requestLegacyExternalStorage="true"
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.DemoSimpleFile"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
            <meta-data
                android:name="ScopedStorage"
                android:value="true" />
        </activity>
    </application>

</manifest>

注意以上的4行<uses-permission>。

后端代码

文件读写帮助类-SDFileUtility.java

package org.mk.android.demo;

import android.content.Context;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class SDFileUtility {
    private final static String TAG = "DemoSimpleFile";
    private Context context;

    public SDFileUtility() {
    }

    public SDFileUtility(Context context) {
        super();
        this.context = context;
    }

    //往SD卡写入文件的方法
    public void savaFileToSD(String fileName, String fileContents) throws Exception {
        //如果手机已插入sd卡,且app具有读写sd卡的权限
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            fileName = Environment.getExternalStorageDirectory().getCanonicalPath() + "/" + fileName;
            //这里就不要用openFileOutput了,那个是往手机内存中写数据的
            FileOutputStream output = null;
            try {
                output = new FileOutputStream(fileName);
                output.write(fileContents.getBytes());
                //将String字符串以字节流的形式写入到输出流中
            } catch (Exception e) {
                Log.e(TAG, "saveFileTOSD error: " + e.getMessage(), e);
            } finally {
                try {
                    output.close();
                    //关闭输出流
                } catch (Exception e) {
                }
            }

        } else Toast.makeText(context, "SD卡不存在或者不可读写", Toast.LENGTH_SHORT).show();
    }

    //读取SD卡中文件的方法
    //定义读取文件的方法:
    public String readFromSD(String fileName) throws IOException {
        StringBuilder sb = new StringBuilder("");
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            fileName = Environment.getExternalStorageDirectory().getCanonicalPath() + "/" + fileName;
            FileInputStream input = null;
            try {
                //打开文件输入流
                input = new FileInputStream(fileName);
                byte[] temp = new byte[1024];

                int len = 0;
                //读取文件内容:
                while ((len = input.read(temp)) > 0) {
                    sb.append(new String(temp, 0, len));
                }
            } catch (Exception e) {
                Log.e(TAG, "readFromSD error: " + e.getMessage(), e);
            } finally {
                try {
                    //关闭输入流
                    input.close();
                } catch (Exception e) {
                }
            }

        }
        return sb.toString();
    }
}

后端主交互类-MainActivity.java

package org.mk.android.demo;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private EditText editFileName;
    private EditText editContents;
    private Button buttonSave;
    private Button buttonClean;
    private Button buttonRead;
    private Context mContext;
    private final static String TAG = "DemoSimpleFile";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = getApplicationContext();
        bindViews();
    }

    private void bindViews() {
        editFileName = (EditText) findViewById(R.id.editFileName);
        editContents = (EditText) findViewById(R.id.editFileContents);
        buttonSave = (Button) findViewById(R.id.buttonSave);
        buttonClean = (Button) findViewById(R.id.buttonClean);
        buttonRead = (Button) findViewById(R.id.buttonRead);

        buttonSave.setOnClickListener(this);
        buttonClean.setOnClickListener(this);
        buttonRead.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.buttonClean:
                editContents.setText("");
                editFileName.setText("");
                break;
            case R.id.buttonSave:
                if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.R) {
                    Log.i(TAG,">>>>>>version.SDK->"+Build.VERSION.SDK_INT);
                    if (!Environment.isExternalStorageManager()) {
                        Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
                        this.startActivity(intent);
                        return;
                    }
                }
                Log.i(TAG,">>>>>>start to writeFile");
                writeFile();
                Log.i(TAG,">>>>>>write success");

                break;
            case R.id.buttonRead:
                if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.R) {
                    Log.i(TAG,">>>>>>version.SDK->"+Build.VERSION.SDK_INT);
                    if (!Environment.isExternalStorageManager()) {
                        Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
                        this.startActivity(intent);
                        return;
                    }
                }
                Log.i(TAG,">>>>>>start to readFile");
                readFile();
                Log.i(TAG,">>>>>>read success");

                break;
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 1 && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
            //writeFile();
            Log.i(TAG,">>>>>>onRequestPermissionsResult");
        }
    }

    private void writeFile() {
        String fileName = editFileName.getText().toString();
        String fileContents = editContents.getText().toString();
        SDFileUtility sdHelper = new SDFileUtility(mContext);
        try {
            sdHelper.savaFileToSD(fileName, fileContents);
            Toast.makeText(getApplicationContext(), "数据写入成功", Toast.LENGTH_SHORT).show();
        } catch (Exception e) {
            Log.e(TAG, "save contents into file has errors: " + e.getMessage(), e);
            Toast.makeText(getApplicationContext(), "数据写入失败", Toast.LENGTH_SHORT).show();
        }
    }

    private void readFile() {
        String detail = "";
        SDFileUtility sdHelper2 = new SDFileUtility(mContext);
        try {
            String fileName2 = editFileName.getText().toString();
            detail = sdHelper2.readFromSD(fileName2);
        } catch (Exception e) {
            Log.e(TAG, "read contents from file has errors: " + e.getMessage(), e);
        }
        Toast.makeText(getApplicationContext(), detail, Toast.LENGTH_SHORT).show();
    }
}

核心代码导读

读写手机SD卡,我们除了在AndroidManifest.xml文件中静态申请权限外还需要使用代码动态申请权限,这是Android6后的权限限制带来的问题。

case R.id.buttonSave:
     if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.R) {
       Log.i(TAG,">>>>>>version.SDK->"+Build.VERSION.SDK_INT);
       if (!Environment.isExternalStorageManager()) {
         Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
         his.startActivity(intent);
         return;
       }
     }

这一段代码就是使用代码在写文件前动态申请权限用的,当这段代码执行后会弹出以下这样的一个对话框

 点击这个APP应用,然后来到第二个对话框

 点击我红圈处标出的开关按钮

 然后重新运行APP即可。

运行效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/100170.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

毕业设计 - 基于SSH的任务调度系统的设计与实现 【源码+论文】

文章目录前言一、项目设计1. 模块设计2. 实现效果二、部分源码项目源码前言 今天学长向大家分享一个 Java web 毕业设计项目: 基于SSH的任务调度系统的设计与实现 一、项目设计 1. 模块设计 根据需求调研结果确定本任务调度系统的功能结构&#xff0c;最终系统实现的系统将…

Django

文章目录基础知识创建项目启动项目创建超级用户创建项目构建个人博客网站简单构建开启本地虚拟环境初步创建blog应用常用的模板标签和过滤器注&#xff1a;常用的模板标签注&#xff1a;常用的过滤器模板嵌套全局模板文件夹模板文件设置建议使用css美化页面导航栏页面美化css框…

捋一捋什么是MySQL插入意向锁?

Insert Intention Lock&#xff0c;中文我们也称之为插入意向锁。 这个可以算是对我们之前所讲的 Gap Lock 的一个补充&#xff0c;关于 Gap Lock&#xff0c;如果还有小伙伴不懂&#xff0c;可以参考&#xff1a;聊一聊MySQL的记录锁、间隙锁与 Next-Key Lock。 1. 为什么需…

Java基础之《netty(14)—异步模型》

一、基本介绍 1、异步的概念和同步相对。当一个异步过程调用发出后&#xff0c;调用者不能立刻得到结果。实际处理这个调用的组件在完成后&#xff0c;通过状态、通知和回调来通知调用者。 2、netty中的I/O操作是异步的&#xff0c;包括Bind、Write、Connect等操作会简单的返…

【云原生 | 47】etcdctl客户端的使用方法详解

&#x1f341;博主简介&#xff1a; &#x1f3c5;云计算领域优质创作者 &#x1f3c5;2022年CSDN新星计划python赛道第一名 &#x1f3c5;2022年CSDN原力计划优质作者 &#x1f3c5;阿里云ACE认证高级工程师 &#x1f3c5;阿里云开发者社区专…

后台基础权限框架搭建实现[木字楠博客]

文章目录1、项目整合SpringSecurity1.1、引入SpringSecurity依赖1.2、启动测试1.3、自定义实体类继承UserDetails1.4、自定义配制文件1.5、重写loadUserByUsername方法1.6、自定义匿名访问注解1.8、编写SpringSecurity配制类后台权限框架搭建&#xff1a;本项目权限主要依赖Spr…

Polynomial Round 2022 (Div. 1 + Div. 2, Rated, Prizes!) A-C

比赛链接 目录 A. Add Plus Minus Sign 题意&#xff1a; 思路&#xff1a; 代码&#xff1a; B. Coloring 题意&#xff1a; 思路&#xff1a; 代码&#xff1a; C. Ice and Fire 题意&#xff1a; 思路&#xff1a; 代码&#xff1a; A. Add Plus Minus Sign 题意…

半导体芯片制造过程可以用哪种测量仪器

近年来&#xff0c;面对持续高涨的芯片需求&#xff0c;半导体行业生产迎来了高难度挑战——对芯片工艺要求更精细&#xff0c;从5nm到3nm&#xff0c;甚至是2nm。“先进封装”的提出&#xff0c;是对技术的新要求&#xff0c;也是对封装工艺中材料和设备的全新考验。 芯片身上…

节点电力市场生产商的战略竞标:凸松弛方法(Matlab实现)

目录 1 电力市场 1.1 什么是电力市场 1.2 电力市场发展历程 1.3 对传统电力系统理论的挑战 2 节点电力市场生产商的战略竞标&#xff1a;凸松弛方法 2.1 简介 2 Matlab代码 1 电力市场 1.1 什么是电力市场 市场&#xff1a;商品交换(交换商品的过程称交易)关系的总和 …

pikachu靶场验证码绕过详解

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是pikachu靶场验证码绕过详解。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严禁对…

endo-BCN-PEG3-Biotin,endo-BCN三聚乙二醇-生物素

【中文名称】endo-BCN三聚乙二醇-生物素 【英文名称】 endo-BCN-PEG3-Biotin&#xff0c;BCN-PEG3-Biotin (endo) 【CAS号】1263166-92-2 【分子式】C29H46N4O7S 【分子量】594.77 【基团部分】BCN 【纯度标准】95% 【外观颜色】 白色固体 &#xff08;具体由其分子量大小决定…

MyBatis学习 | 简介HelloWord

文章目录一、简介二、HelloWord2.1 环境搭建2.2 创建全局配置文件2.3 创建工具类2.4 创建数据库表和对应的JavaBean2.5 创建SQL映射文件2.6 非接口式与接口式编程2.6.1 非接口式编程2.6.2 接口式编程⭐2.7 简单总结学习地址&#x1f517; https://www.bilibili.com/video/BV1mW…

动态规划问题——换钱的方法数

题目&#xff1a; 给定数组arr&#xff0c;arr中所有的值都为正数且不重复。每个值代表一种面值的货币&#xff0c;每种面值的货币可以使用任意张&#xff0c;再给定一个整数aim&#xff0c;代表要找的钱数&#xff0c;求换钱有多少种方法。 举例&#xff1a; arr [5, 10, 2…

【PCL1.11.0+win10+vs2019】环境配置/ 点云格式转换及可视化

文章目录一、安装1.1 下载PCL1.2 安装PCL1.3 安装OSGeo4W二、配置2.1 配置环境变量2.2 配置VS2019三、点云格式转换以及可视化参考一、安装 1.1 下载PCL 首先我们需要下载pcl1.11.0 &#xff0c;这个版本与vs2019对应。 有两种下载方法&#xff1a;百度网盘、官网下载。二选一…

docker原理及服务编排

一、什么是docker Docker 是一个开源项目&#xff0c;诞生于2013年初&#xff0c;最初是dotCloud公司内部的一个业余项目。它基于Google公司推出的Go语言实现。项目后来加入了Linux基金会&#xff0c;遵从了Apache 2.0协议&#xff0c;项目代码在GitHub上进行维护。 Docker 项…

【毕业设计_课程设计】基于Spark网易云音乐数据分析

文章目录0 项目说明1 系统模块2 分析内容3 界面展示4 项目工程0 项目说明 基于Spark网易云音乐数据分析 提示&#xff1a;适合用于课程设计或毕业设计&#xff0c;工作量达标&#xff0c;源码开放 1 系统模块 包含爬虫,Scala代码,Spark,Hadoop,ElasticSearch,logstash,Flume…

基于ChatGPT实现微信智能机器人

ChatGPT近期以强大的对话和信息整合能力风靡全网&#xff0c;可以写代码、改论文、讲故事&#xff0c;几乎无所不能&#xff0c;这让人不禁有个大胆的想法&#xff0c;能否用他的对话模型把我们的微信打造成一个智能机器人&#xff0c;可以在与好友对话中给出意想不到的回应&am…

汇编语言笔记——接口技术与编程

文章目录传送门储存系统与技术材料高速储存器缓冲储存器&#xff08;Cache&#xff09;材料&#xff0c;局部性&#xff0c;访问方式Cache全相联映射Cache交换与一致性单核CPU一致性处理多核CPU的MESI协议主储存器&#xff08;内存&#xff09;主要技术指标容量带宽内存模组与内…

【JavaWeb】Servlet

Servlet简介 Servlet是sun公司开发动态web的一门技术Sun在这些API中提供一个接口叫做&#xff1a;Servlet&#xff0c;如果想开发一个Servlet程序&#xff0c;需要编写一个类&#xff0c;实现Servlet接口把开发好的Java类部署到web服务器中 把实现了Servlet接口的Java程序叫做…

【Anime.js】——Anime.js源码核心理解

一、Anime.js整体结构 Anime.js的强大之处在于代码量非常少&#xff0c;但功能却非常强大。让我们一起来探索Anime.js源码的核心吧~ Anime.js之所以能如此强大主要是因为它的代码结构设计的非常巧妙合理&#xff0c;所以我们想要掌握Anime.js的核心&#xff0c;首先我们要了解…