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開(kāi)頭的路徑都是內(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開(kāi)頭的,比如說(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-01Android開(kāi)發(fā)手冊(cè)Button按鈕實(shí)現(xiàn)點(diǎn)擊音效
這篇文章主要為大家介紹了Android開(kāi)發(fā)手冊(cè)Button按鈕實(shí)現(xiàn)點(diǎn)擊音效示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06Android編程實(shí)現(xiàn)添加低電流提醒功能的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)添加低電流提醒功能的方法,涉及Android廣播監(jiān)聽(tīng)及電源監(jiān)控等相關(guān)操作技巧,需要的朋友可以參考下2017-09-09Android開(kāi)發(fā)之TabHost選項(xiàng)卡及相關(guān)疑難解決方法
這篇文章主要介紹了Android開(kāi)發(fā)之TabHost選項(xiàng)卡及相關(guān)疑難解決方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android開(kāi)發(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-12Android使用criteria選擇合適的地理位置服務(wù)實(shí)現(xiàn)方法
這篇文章主要介紹了Android使用criteria選擇合適的地理位置服務(wù)實(shí)現(xiàn)方法,實(shí)例分析了Criteria的具體使用技巧,需要的朋友可以參考下2016-01-01Android 中okhttp自定義Interceptor(緩存攔截器)
這篇文章主要介紹了Android 中okhttp自定義Interceptor(緩存攔截器)的相關(guān)資料,需要的朋友可以參考下2017-03-03