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

Posted TGITCIC

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android入门第50天-读写本地文件相关的知识,希望对你有一定的参考价值。

简介

为了这个系列,我的代码已经准备到了第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即可。

运行效果

以上是关于Android入门第50天-读写本地文件的主要内容,如果未能解决你的问题,请参考以下文章

Android入门第9天-Android读本地JSON文件并显示

Android入门第55天-在Android里使用OKHttp组件访问网络资源

Android入门第30天-Android里的Toast的使用

Android入门第22天-Android里的计时器Chronometer的使用

Android入门第43天-Activity与Activity间的互相传值

Android入门第16天-Android里的SwitchButton的使用