Android文件讀寫的幾種方式
Android的App可以讀寫的位置為:
一、內(nèi)置data目錄下對(duì)應(yīng)app名稱的目錄;
二、擴(kuò)展SD卡(包括虛擬的內(nèi)置SD卡和外置SD卡);
一、先說(shuō)說(shuō)內(nèi)置data目錄下文件的讀寫。
內(nèi)置data目錄即內(nèi)部存儲(chǔ),指的是應(yīng)用內(nèi)部獨(dú)有的存儲(chǔ),這部分存儲(chǔ)的文件、數(shù)據(jù),只能被應(yīng)用自身訪問(wèn)到,其他應(yīng)用都沒(méi)有權(quán)限訪問(wèn)。
一般情況下,/data開頭的路徑都是內(nèi)部存儲(chǔ)。而一般應(yīng)用所能夠訪問(wèn)到的就是下面幾個(gè)路徑,稱為應(yīng)用內(nèi)部私有存儲(chǔ)。
應(yīng)用內(nèi)部私有存儲(chǔ):
/data/user/0/<包名>
/data/user/0/<包名>/files #存放文件數(shù)據(jù)
/data/user/0/<包名>/databases #存放Sqlite的數(shù)據(jù)庫(kù)文件
/data/user/0/<包名>/shared_prefs #存放SharedPreference的數(shù)據(jù)
/data/user/0/<包名>/cache #存放緩存文件
一旦App被卸載,系統(tǒng)將會(huì)移除內(nèi)部存儲(chǔ)中相關(guān)應(yīng)用的數(shù)據(jù)。
方式1:內(nèi)置API讀寫
這個(gè)位置的讀寫有提供一套單獨(dú)的API來(lái)讀寫,無(wú)需申明特殊權(quán)限。
代碼中有個(gè)openFileInput的方法,這個(gè)方法是Android內(nèi)置的,需放在Activity中才能執(zhí)行。
如下:
//讀取內(nèi)置data目錄下文件
public String readDataFile(String fileName) {
String res = "";
try {
FileInputStream fin = openFileInput(fileName);
int length = fin.available();
byte[] buffer = new byte[length];
fin.read(buffer);
res = new String(buffer);
fin.close();
} catch (Exception e) {
e.printStackTrace();
Log.e("Exception", "readDataFile Error!" + e.getMessage());
}
return res;
}
//寫入內(nèi)置data目錄下文件
private void writeDataFile(String fileName, String content) {
try {
FileOutputStream fut = openFileOutput(fileName, Context.MODE_PRIVATE | Context.MODE_APPEND);
byte[] bytes = content.getBytes();
fut.write(bytes);
fut.close();
} catch (Exception e) {
e.printStackTrace();
Log.e("Exception", "writeDataFile Error!" + e.getMessage());
}
}測(cè)試代碼:
String fileName="test.txt";
writeDataFile(fileName, "Hello Android");
String txt = readDataFile(fileName);
Log.e("txt", txt);方式2:獲取對(duì)應(yīng)的data路徑后,通過(guò)普通的方法讀寫data中的文件。
手動(dòng)獲取拼接data目錄下文件路徑,然后用通用的文件讀寫方式進(jìn)行讀寫。
通用讀寫文件的輔助類,F(xiàn)ileHelper.java
package com.rc114.scanner;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.URLDecoder;
public class FileHelper {
public static String combinePath(String path1, String path2) {
File file1 = new File(path1);
File file2 = new File(file1, path2);
return file2.getPath();
}
/**
* 讀取文件
*
* @param filepath 文件路徑
*/
public static String readFile(String filepath) {
String encoding = "UTF-8";
return readFile(filepath, encoding);
}
/**
* 讀取文件,指定編碼
*
* @param filepath 文件路徑
*/
public static String readFile(String filepath, String encoding) {
try {
filepath = URLDecoder.decode(filepath, "utf-8");
File file = new File(filepath);
Long filelength = file.length();
byte[] filecontent = new byte[filelength.intValue()];
FileInputStream in = new FileInputStream(file);
in.read(filecontent);
in.close();
return new String(filecontent, encoding);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
/**
* 將字符串寫入文件
*
* @param filepath
* @param text
* @param isAppend
*/
public static void writeFile(String filepath, String text, boolean isAppend) {
try {
filepath = URLDecoder.decode(filepath, "utf-8");
File file = new File(filepath);
File parentFile = file.getParentFile();
if (!parentFile.exists()) {
parentFile.mkdirs();
}
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream f = new FileOutputStream(filepath, isAppend);
f.write(text.getBytes());
f.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void writeFile(String filepath, String text, String encodeing) {
try {
filepath = URLDecoder.decode(filepath, "utf-8");
File file = new File(filepath);
File parentFile = file.getParentFile();
if (!parentFile.exists()) {
parentFile.mkdirs();
}
if (!file.exists()) {
file.createNewFile();
}
// FileOutputStream f = new FileOutputStream(filepath, "GBK");
// f.write(text.getBytes());
// f.close();
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(filepath), encodeing);
writer.append(text);
writer.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}測(cè)試代碼:
//獲取data目錄下對(duì)應(yīng)包名根目錄
String dataDir = Environment.getDataDirectory().getPath() + "/data/" + packageName;
//拼接待讀寫文件路徑
String filepath = FileHelper.combinePath(dataDir, "test.txt");
//寫入文件
FileHelper.writeFile(filepath, "Hello", "utf-8");
//讀取文件
String txt = FileHelper.readFile(filepath);
Log.e("txt", txt);二、擴(kuò)展SD卡文件讀寫
擴(kuò)展SD卡文件即外部存儲(chǔ),指的是是公共的存儲(chǔ),這部分存儲(chǔ)理論上是全局可見(jiàn)的,所有的應(yīng)用都可以訪問(wèn)這部分?jǐn)?shù)據(jù),一般情況下,路徑都是以/storage開頭的,比如說(shuō)/storage/emulated/0就是屬于外部存儲(chǔ),這個(gè)路徑的實(shí)際的掛載點(diǎn)是/data/media。又比如外置sdcard的路徑為/storage/13FC-0F0B。 相比較內(nèi)部存儲(chǔ)一定會(huì)存在,外部存儲(chǔ)可能是sdcard或者通過(guò)otg掛載的U盤形式,所以可能出現(xiàn)沒(méi)有掛載的情況,所以所有的外部存儲(chǔ)要在使用前通過(guò)下面的方式判斷是否有被掛載。
/*檢查外部存儲(chǔ)是否可寫*/
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
/*檢查外部存儲(chǔ)是否可讀*/
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}訪問(wèn)外部存儲(chǔ)需在AndroidManifest.xml文件中申明權(quán)限:
<!-- 存儲(chǔ)權(quán)限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" tools:ignore="ProtectedPermissions" />
安卓6.0以后,谷歌要求危險(xiǎn)權(quán)限必須動(dòng)態(tài)獲取,所以還要使用requestPermissions在運(yùn)行時(shí)獲取權(quán)限。
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private static int REQUEST_PERMISSION_CODE = 100;
//獲取權(quán)限
private void getPermission() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_PERMISSION_CODE);
} else {
boolean writable = isExternalStorageWritable();
boolean readable = isExternalStorageReadable();
Log.e("外部存儲(chǔ)讀寫", "寫:" + writable + "-讀:" + readable);
File root = Environment.getExternalStorageDirectory();//取得外部存儲(chǔ)根路徑
File[] files = root.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
Log.e("文件夾", files[i].toString());
}
}
}
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_PERMISSION_CODE) {
for (int i = 0; i < permissions.length; i++) {
Log.i("MainActivity", "申請(qǐng)的權(quán)限為:" + permissions[i] + ",申請(qǐng)結(jié)果:" + grantResults[i]);
}
}
}在Activity的onCreate事件中執(zhí)行g(shù)etPermission()方法,動(dòng)態(tài)獲取存儲(chǔ)權(quán)限。
完成了上面的操作后,在代碼:
File root = Environment.getExternalStorageDirectory();//取得外部存儲(chǔ)根路徑 File[] files = root.listFiles();
中,root.listFiles()可能會(huì)返回null,還是無(wú)法讀取或?qū)懭胛募?/p>
查了下資料,Android 10 或更高版本,還需要做一個(gè)配置:在AndroidManifest.xml中,還需增加:android:requestLegacyExternalStorage="true"

利用上面的FileHelper.java類,測(cè)試寫入一個(gè)文件:
File root = Environment.getExternalStorageDirectory(); FileHelper.writeFile(FileHelper.combinePath(root.getPath(), "text.txt"), "Hello", false);
測(cè)試遍歷根目錄:
File root = Environment.getExternalStorageDirectory();
File[] files = root.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
Log.e("文件夾", files[i].toString());
}
if (files[i].isFile()) {
Log.e("文件", files[i].toString());
}
}
}輸出結(jié)果:

至此,完成了外部存儲(chǔ)的讀寫功能。
參考資料:
??????1.Android中的內(nèi)部存儲(chǔ)和外部存儲(chǔ)
2.android - Environment.getExternalStorageDirectory() deprecation alternatives - Stack Overflow
總結(jié)
到此這篇關(guān)于Android文件讀寫的幾種方式的文章就介紹到這了,更多相關(guān)Android文件讀寫內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android UI動(dòng)態(tài)設(shè)置帶有Stroke漸變色背景Drawable
這篇文章主要為大家介紹了Android UI動(dòng)態(tài)設(shè)置帶有Stroke漸變色背景Drawable,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
Android開發(fā)手冊(cè)Button按鈕實(shí)現(xiàn)點(diǎn)擊音效
這篇文章主要為大家介紹了Android開發(fā)手冊(cè)Button按鈕實(shí)現(xiàn)點(diǎn)擊音效示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Android編程實(shí)現(xiàn)添加低電流提醒功能的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)添加低電流提醒功能的方法,涉及Android廣播監(jiān)聽及電源監(jiān)控等相關(guān)操作技巧,需要的朋友可以參考下2017-09-09
Android開發(fā)之TabHost選項(xiàng)卡及相關(guān)疑難解決方法
這篇文章主要介紹了Android開發(fā)之TabHost選項(xiàng)卡及相關(guān)疑難解決方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android開發(fā)中TabHost選項(xiàng)卡的常見(jiàn)用法以及相關(guān)疑難問(wèn)題解決方法,需要的朋友可以參考下2019-03-03
詳解Android SpannableString多行圖文混排的應(yīng)用實(shí)戰(zhàn)
本篇文章主要介紹了Android SpannableString多行圖文混排的應(yīng)用實(shí)戰(zhàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12
Android使用criteria選擇合適的地理位置服務(wù)實(shí)現(xiàn)方法
這篇文章主要介紹了Android使用criteria選擇合適的地理位置服務(wù)實(shí)現(xiàn)方法,實(shí)例分析了Criteria的具體使用技巧,需要的朋友可以參考下2016-01-01
Android 中okhttp自定義Interceptor(緩存攔截器)
這篇文章主要介紹了Android 中okhttp自定義Interceptor(緩存攔截器)的相關(guān)資料,需要的朋友可以參考下2017-03-03

