Android入門之讀寫本地文件的實現(xiàn)
簡介
為了這個系列,我的代碼已經(jīng)準(zhǔn)備到了第150天了。接下來的內(nèi)容會越來越精彩,我們也越來越開始進(jìn)入Android的一些高級功能上的編程了。今天我們就要講Android中對本地文件進(jìn)行讀寫的全過程。
課程目標(biāo)

- 輸入文件名、輸入文件內(nèi)容后按【保存到SD卡】,可以把文件保存到SD卡根目錄;
- 輸入文件名,按【讀取SD卡中的文件】,可以根據(jù)輸入的文件名把文件內(nèi)容顯示成Toast;
- 搞清Android中對于SD卡讀寫時所需要的靜態(tài)權(quán)限申請、動態(tài)權(quán)限申請;
以上一共我們有3個目標(biāo),根據(jù)目標(biāo)下面開始教程。
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="清輸入文件內(nèi)容" />
<EditText
android:id="@+id/editFileContents"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="文件內(nèi)容" />
<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從上到下依次把一系列元素都設(shè)置好。接著我們來看我們的后端代碼。
靜態(tài)授權(quán)-AndroidManifest.xml文件內(nèi)容
<?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中創(chuàng)建與刪除文件權(quán)限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
tools:ignore="ProtectedPermissions" />
<!-- 往SDCard寫入數(shù)據(jù)權(quán)限 -->
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<!--外部存儲的寫權(quán)限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--外部存儲的讀權(quán)限-->
<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卡的權(quán)限
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
fileName = Environment.getExternalStorageDirectory().getCanonicalPath() + "/" + fileName;
//這里就不要用openFileOutput了,那個是往手機內(nèi)存中寫數(shù)據(jù)的
FileOutputStream output = null;
try {
output = new FileOutputStream(fileName);
output.write(fileContents.getBytes());
//將String字符串以字節(jié)流的形式寫入到輸出流中
} catch (Exception e) {
Log.e(TAG, "saveFileTOSD error: " + e.getMessage(), e);
} finally {
try {
output.close();
//關(guān)閉輸出流
} 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;
//讀取文件內(nèi)容:
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 {
//關(guān)閉輸入流
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(), "數(shù)據(jù)寫入成功", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Log.e(TAG, "save contents into file has errors: " + e.getMessage(), e);
Toast.makeText(getApplicationContext(), "數(shù)據(jù)寫入失敗", 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();
}
}核心代碼導(dǎo)讀
讀寫手機SD卡,我們除了在AndroidManifest.xml文件中靜態(tài)申請權(quán)限外還需要使用代碼動態(tài)申請權(quán)限,這是Android6后的權(quán)限限制帶來的問題。
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;
}
}這一段代碼就是使用代碼在寫文件前動態(tài)申請權(quán)限用的,當(dāng)這段代碼執(zhí)行后會彈出以下這樣的一個對話框

點擊這個APP應(yīng)用,然后來到第二個對話框

點擊我紅圈處標(biāo)出的開關(guān)按鈕

然后重新運行APP即可。
運行效果


到此這篇關(guān)于Android入門之讀寫本地文件的實現(xiàn)的文章就介紹到這了,更多相關(guān)Android讀寫本地文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android實現(xiàn)隨意拖動View效果的實例代碼
這篇文章主要介紹了Android實現(xiàn)隨意拖動View效果,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-07-07
使用Android開發(fā)接入第三方原生SDK實現(xiàn)微信登錄
這篇文章主要介紹了使用Android開發(fā)接入第三方原生SDK實現(xiàn)微信登錄,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03
Android開發(fā)之ViewPager實現(xiàn)滑動切換頁面
這篇文章主要為大家詳細(xì)介紹了Android開發(fā)之ViewPager實現(xiàn)滑動切換頁面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-09-09
android當(dāng)前apn的狀態(tài)以及獲取方法
在絕大多數(shù)android機器etc路徑下存放一個的apns-conf.xml文件,表示當(dāng)前機器使用的apn信息通過root機器可以push出來看看,具體路徑可以上網(wǎng)搜下,接下來介紹獲取apn的狀態(tài)的方法2013-01-01
Android編程實現(xiàn)動態(tài)更新ListView的方法
這篇文章主要介紹了Android編程實現(xiàn)動態(tài)更新ListView的方法,結(jié)合實例形式詳細(xì)分析了ListView的布局及動態(tài)更新實現(xiàn)方法,需要的朋友可以參考下2016-02-02
Android基于google Zxing實現(xiàn)各類二維碼掃描效果
這篇文章主要介紹了Android基于google Zxing實現(xiàn)各類二維碼掃描效果的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-02-02
Android開發(fā)實現(xiàn)SubMenu選項菜單和子菜單示例
這篇文章主要介紹了Android開發(fā)實現(xiàn)SubMenu選項菜單和子菜單,結(jié)合實例形式分析了Android開發(fā)中SubMenu選項菜單和子菜單的功能、配置、布局等相關(guān)操作技巧,需要的朋友可以參考下2019-03-03

