简介

为了这个系列,我的代码已经准备到了第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"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="清输入文件名" /><EditTextandroid:id="@+id/editFileName"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="文件名" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="清输入文件内容" /><EditTextandroid:id="@+id/editFileContents"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="文件内容" /><Buttonandroid:id="@+id/buttonSave"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="保存到SD卡" /><Buttonandroid:id="@+id/buttonClean"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="清空" /><Buttonandroid: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" /><applicationandroid: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"><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter><meta-dataandroid:name="android.app.lib_name"android:value="" /><meta-dataandroid:name="ScopedStorage"android:value="true" /></activity></application></manifest>

注意以上的6行<uses-permission>以及AndroidManifest.xml文件中这一句,都必须加上。

后端代码

文件读写帮助类-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";@Overrideprotected 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);}@Overridepublic 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;}}@Overridepublic 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即可。

运行效果

Android入门第50天-读写本地文件相关推荐

  1. Android入门第七篇之ListView (二)

    Android入门第六篇之ListView (一) ,讲的是如何制作一个具有两行文本的 自定义控件 ,作为ListView的Item的使用方法.这篇接下来也是围绕ListView和Item,更加深入地 ...

  2. Android 入门第四讲03-列表RecyclerView(RecyclerView使用步骤(详),RecyclerView指定一行item的数目+指定一行item的数量,并且设置列表方向)

    Android 入门第四讲03-列表RecyclerViewRecyclerView使用步骤(详),RecyclerView指定一行item的数目+指定一行item的数量,并且设置列表方向) 1.Re ...

  3. chrome html 读写文件路径,Chrome浏览器支持直接读写本地文件了

    本文首发于公众号:符合预期的CoyPan 写在前面 最新版的Chrome(Chrome 83, 须要开启权限)支持直接读写本地文件了.javascript 开启方法:Chrome浏览器升级到83版本以 ...

  4. java 读写文件乱码_Java 解决读写本地文件中文乱码的问题

    Java 解决读写本地文件中文乱码的问题 前言: 在用Java程序进行读写含中文的txt文件时,经常会出现读出或写入的内容会出现乱码.原因其实很简单,就是系统的编码和程序的编码采用了不同的编码格式.通 ...

  5. OOB与COM交互读写本地文件

    相信读过前几篇Silverlight Out of Browser实例教程的朋友已经对Silverlight的OOB应用有了一定的认识和了解.今天,我们将讨论Silverlight Out of Br ...

  6. Android Studio Webview加载assets本地文件

    1.新建assets资源文件 右键单击main目录,选择New>Folder>Assets Folder. 勾选Change Folder Location可改变其默认路径 在Assets ...

  7. Chrome 83 发布,支持直接读写本地文件!新的跨域策略!

    Chrome 稳定版本的更新直接跳过 v82 来到 Chrome 83,因此很多原本在 Chrome 82上就要正式发布的功能也悉数积攒到了本次更新的 Chrome 83 中. 速览 本地文件系统 新 ...

  8. Groovy里读写本地文件的几种方式

    方法1和方法2分别如下图红色和蓝色高亮所示: 其中第八行的双引号包裹起来的变量代表GString,即JavaScript和ABAP里的字符串模板. 代码: new File('c:\\temp', ' ...

  9. JavaScript创建与读写本地文件(IEFirefox)

    在IE下,可以使用ActiveXObject来实现 var fso = new ActiveXObject("Scripting.FileSystemObject"); var f ...

最新文章

  1. C++/C++11中std::priority_queue的使用
  2. mysql5.7忘记root密码的修改方法
  3. [转]奇文-闲话操作系统(1/4)
  4. 用CMD命令实现一个简单的网页搜索
  5. openssl NDK 交叉编译
  6. java消息 框架_java 框架-消息队列ActiveMQ
  7. 使用CSS属性处理前端开发中长文本造成的内容显示重叠问题
  8. SpringBoot中yaml配置
  9. position的用法小结
  10. 20. yii 2 分页
  11. CSDN账号被盗了吗?
  12. 新动态视频壁纸微信小程序源码_支持多种分类短视频-也有静态壁纸
  13. 迅为iTOP6818开发板QtE5.7应用例程源码
  14. ADB常用命令(adb常用命令)
  15. 《C程序设计语言》笔记 第6章 结构
  16. 百分百解决 mbatis/mp报错 Invalid bound statement (not found)
  17. 【设计模式】之抽象工厂模式
  18. 三菱FX3U——ST编程中的字符串
  19. 展锐Android11安兔兔显示的光圈值修正
  20. 程序员放松的8个好网站推荐

热门文章

  1. 2012端午檀头山碧海蓝天海岛游~ ZZ
  2. A股-入门-弱市中如何把握超跌股的机会
  3. MAC程序坞0响应设置
  4. 通过电影票房预测来一览机器学习一般流程
  5. 回溯-LeetCode77. 组合(Python)
  6. css水平垂直居中各种方法实现方式
  7. 公文轻松搞定!简单实用的红头专色文印技巧
  8. 一个GISER 6.7的祝福
  9. 外企, 私企和国企, 不同的软件开发流程感受
  10. 应用、游戏和品牌的新营销方式-试玩广告