Android入門之讀寫本地文件的實(shí)現(xiàn)
簡(jiǎn)介
為了這個(gè)系列,我的代碼已經(jīng)準(zhǔn)備到了第150天了。接下來(lái)的內(nèi)容會(huì)越來(lái)越精彩,我們也越來(lái)越開始進(jìn)入Android的一些高級(jí)功能上的編程了。今天我們就要講Android中對(duì)本地文件進(jìn)行讀寫的全過程。
課程目標(biāo)
- 輸入文件名、輸入文件內(nèi)容后按【保存到SD卡】,可以把文件保存到SD卡根目錄;
- 輸入文件名,按【讀取SD卡中的文件】,可以根據(jù)輸入的文件名把文件內(nèi)容顯示成Toast;
- 搞清Android中對(duì)于SD卡讀寫時(shí)所需要的靜態(tài)權(quán)限申請(qǐng)、動(dòng)態(tài)權(quán)限申請(qǐng);
以上一共我們有3個(gè)目標(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端很簡(jiǎn)單,用LinearLayout從上到下依次把一系列元素都設(shè)置好。接著我們來(lái)看我們的后端代碼。
靜態(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" /> <!--外部存儲(chǔ)的寫權(quán)限--> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!--外部存儲(chǔ)的讀權(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 { //如果手機(jī)已插入sd卡,且app具有讀寫sd卡的權(quán)限 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { fileName = Environment.getExternalStorageDirectory().getCanonicalPath() + "/" + fileName; //這里就不要用openFileOutput了,那個(gè)是往手機(jī)內(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)讀
讀寫手機(jī)SD卡,我們除了在AndroidManifest.xml文件中靜態(tài)申請(qǐng)權(quán)限外還需要使用代碼動(dòng)態(tài)申請(qǐng)權(quán)限,這是Android6后的權(quán)限限制帶來(lái)的問題。
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; } }
這一段代碼就是使用代碼在寫文件前動(dòng)態(tài)申請(qǐng)權(quán)限用的,當(dāng)這段代碼執(zhí)行后會(huì)彈出以下這樣的一個(gè)對(duì)話框
點(diǎn)擊這個(gè)APP應(yīng)用,然后來(lái)到第二個(gè)對(duì)話框
點(diǎn)擊我紅圈處標(biāo)出的開關(guān)按鈕
然后重新運(yùn)行APP即可。
運(yùn)行效果
到此這篇關(guān)于Android入門之讀寫本地文件的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Android讀寫本地文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android實(shí)現(xiàn)隨意拖動(dòng)View效果的實(shí)例代碼
這篇文章主要介紹了Android實(shí)現(xiàn)隨意拖動(dòng)View效果,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07Android實(shí)現(xiàn)底部彈出按鈕菜單升級(jí)版
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)底部彈出按鈕菜單的升級(jí)版,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10使用Android開發(fā)接入第三方原生SDK實(shí)現(xiàn)微信登錄
這篇文章主要介紹了使用Android開發(fā)接入第三方原生SDK實(shí)現(xiàn)微信登錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2020-03-03Android手勢(shì)操作簡(jiǎn)單實(shí)例講解
這篇文章主要為大家詳細(xì)介紹了Android手勢(shì)操作簡(jiǎn)單實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09Android開發(fā)之ViewPager實(shí)現(xiàn)滑動(dòng)切換頁(yè)面
這篇文章主要為大家詳細(xì)介紹了Android開發(fā)之ViewPager實(shí)現(xiàn)滑動(dòng)切換頁(yè)面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-09-09android當(dāng)前apn的狀態(tài)以及獲取方法
在絕大多數(shù)android機(jī)器etc路徑下存放一個(gè)的apns-conf.xml文件,表示當(dāng)前機(jī)器使用的apn信息通過root機(jī)器可以push出來(lái)看看,具體路徑可以上網(wǎng)搜下,接下來(lái)介紹獲取apn的狀態(tài)的方法2013-01-01Android編程實(shí)現(xiàn)動(dòng)態(tài)更新ListView的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)動(dòng)態(tài)更新ListView的方法,結(jié)合實(shí)例形式詳細(xì)分析了ListView的布局及動(dòng)態(tài)更新實(shí)現(xiàn)方法,需要的朋友可以參考下2016-02-02Android基于google Zxing實(shí)現(xiàn)各類二維碼掃描效果
這篇文章主要介紹了Android基于google Zxing實(shí)現(xiàn)各類二維碼掃描效果的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-02-02Android開發(fā)實(shí)現(xiàn)SubMenu選項(xiàng)菜單和子菜單示例
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)SubMenu選項(xiàng)菜單和子菜單,結(jié)合實(shí)例形式分析了Android開發(fā)中SubMenu選項(xiàng)菜單和子菜單的功能、配置、布局等相關(guān)操作技巧,需要的朋友可以參考下2019-03-03Android 自定義縮短Toast顯示時(shí)間的實(shí)例代碼
這篇文章主要介紹了Android 自定義縮短Toast顯示時(shí)間,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01