? ? ? ? Android開發(fā)中,離不開對文件的操作。本文首先介紹了使用java對文件進行基本的讀寫操作,而后介紹了Android中讀取Assets與raw文件夾中的數(shù)據(jù),最后介紹了Android中讀寫內(nèi)部存儲與外部存儲。
詳細(xì)代碼:讀取Assets與raw文件夾中的數(shù)據(jù)? ??讀寫內(nèi)部存儲與外部存儲
一、文件的基本操作
java中file類的定義:An abstract representation of file and directory pathnames.
創(chuàng)建文件時,先實例化file類,再調(diào)用createNewFile方法
傳入文件路徑可以實例化file對象
Filefile=newFile(FileUtil.FILE_NAME);
通過file.exists()可以判斷文件是否存在,存在返回true
//創(chuàng)建文件
file.createNewFile();
可以獲取文件的各種屬性
"文件名為:"+file.getName()"文件的絕對路徑為"+file.getAbsolutePath()
//文件存放在工程根目錄下,相對路徑只有文件名
"文件的相對路徑為"+file.getPath();
//文件大小,單位bytes,"文件大小為:"+file.length()+”字節(jié)"
"文件是否可讀"+file.canRead()"文件是否可寫"+file.canWrite()"文件是否隱藏"+file.isHidden()
文件重命名,調(diào)用renameTo()方法,需要傳入File類作為參數(shù)
Filefile=newFile(FileUtil.FILE_NAME);
FilenewFile=newFile("AnotherFile.txt");
file.renameTo(newFile);
文件重命名只針對文件本身,重命名后File對象不變,調(diào)用getName()會獲得原值
刪除文件,當(dāng)文件存在時,調(diào)用delete()方法刪除文件
Filefile=newFile(FileUtil.FILE_NAME);
if(file.exists()){file.delete();}
創(chuàng)建文件夾,同樣先實例化file類,然后調(diào)用mkDir或mkDirs方法進行文件夾的創(chuàng)建
//文件夾,創(chuàng)建多級目錄時,不能使用"/"作為分隔符,會因為操作系統(tǒng)的不同而出現(xiàn)異常
//需要使用File.separator(File類中默認(rèn)的分隔符)
publicstaticfinalStringFOLDER_NAME="NewFolder2"+File.separator+"SubFolder2”;
//當(dāng)使用file.mkdir時,如果有任意一級的文件夾不存在時都不會完成創(chuàng)建,file.mkdir();
//使用mkdirs創(chuàng)建文件夾時,有文件夾時,創(chuàng)建下一級文件,否則先創(chuàng)建它本身,再創(chuàng)建下一級文件夾
file.mkdirs();創(chuàng)建時盡量使用mkDirs
刪除文件夾,調(diào)用file.delete()方法
二、讀取assets中的文件數(shù)據(jù)
assets目錄下的文件在打包后會原封不動的保存在apk包中,不會被編譯成二進制
用于儲存較小的文件,可以有目錄結(jié)構(gòu),也就是assets目錄下可以再建立文件夾
assets文件夾下的文件不會被映射到R.java中,訪問的時候需要AssetManager類,即不可使用R.id.fileName進行訪問
創(chuàng)建assets文件夾
在項目結(jié)構(gòu)管理區(qū),選擇project視圖,在app/src/main文件夾下,新建assets文件夾
在項目底部根目錄下的xxx.iml文件中進行配置(xxx為項目工程名)
在configuration 標(biāo)簽下,添加option子標(biāo)簽
通過getResource()或AssetsManager的getAssets()方法獲取字節(jié)流,而后通過文件的一般讀取方式進行讀取。
//通過getAssets獲取InputStream獲取字節(jié)流
InputStream is = getResources().getAssets().open("info.txt");
//將字節(jié)流轉(zhuǎn)換為字符流
InputStreamReader isr =newInputStreamReader(is,"UTF-8");
//創(chuàng)建帶緩沖區(qū)的字符流
BufferedReader bfr =newBufferedReader(isr);
//逐行循環(huán)讀取文件
String in ="";
while((in = bfr.readLine()) !=null){
Log.i(TAG,in);
}
三、讀取raw文件夾中的文件數(shù)據(jù)
assets目錄下的文件在打包后會原封不動的保存在apk包中,不會被編譯成二進制
res/raw中的文件會被映射到R.java文件中,訪問的時候直接使用資源ID即R.id.filename;
創(chuàng)建raw目錄,在res目錄下創(chuàng)建raw目錄,將文件儲存在目錄中
通過getResource.openRawResource()將文件讀取為字節(jié)流,由于文件被影射到R.java文件中,所以參數(shù)可以直接使用R.raw.info,而后按照正常的文件讀寫方式讀寫
InputStream is = getResources().openRawResource(R.raw.info);
InputStreamReader isr =newInputStreamReader(is);
BufferedReader bfr =newBufferedReader(isr);
String in ="";
try{
while((in = bfr.readLine()) !=null){
Log.i(TAG,in);
}
四、讀取內(nèi)部(internal storage)儲存的文件數(shù)據(jù)
程序運行后,在當(dāng)前應(yīng)用下的data->data->應(yīng)用目錄下的儲存空間為文件內(nèi)部儲存空間包含cache和code_cache,只對當(dāng)前應(yīng)用可見。使用OpenFileOutput(filename,寫入模式)方法,可以在應(yīng)用內(nèi)部儲存中自動創(chuàng)建files文件夾,在files文件夾中,創(chuàng)建相應(yīng)文件名的文件。
讀取數(shù)據(jù):程序從輸入流讀取數(shù)據(jù),數(shù)據(jù)源為鍵盤,網(wǎng)絡(luò),文件等。
寫入數(shù)據(jù):程序向輸出流寫入數(shù)據(jù),將程序中的數(shù)據(jù)輸出到顯示器,文件,網(wǎng)絡(luò)
寫入數(shù)據(jù):調(diào)用OpenFileOutput(filename,寫入模式)方法,得到FileOutputStream,包裝成OutputStreamWriter,然后調(diào)用write方法進行寫入,沖刷緩沖區(qū),關(guān)閉流
//文件輸出流,第二個參數(shù)為寫入模式,使用openFileOutPut()方法輸出的文件在
//應(yīng)用程序內(nèi)部儲存空間
FileOutputStream fos = openFileOutput(flieName,Context.MODE_PRIVATE);
//將文件輸出流進一步包裝,變?yōu)榭蓪懭胱址腛utPutStreamWriter
OutputStreamWriter osw =newOutputStreamWriter(fos,"UTF-8");
osw.write(et.getText().toString());
//執(zhí)行flush操作,將緩沖區(qū)的數(shù)據(jù)全部輸出
osw.flush();
fos.flush();
//關(guān)閉流,后打開的流先關(guān)閉
osw.close();
fos.close();
Toast.makeText(MainActivity.this,"寫入完成",Toast.LENGTH_SHORT).show();
讀取數(shù)據(jù):調(diào)用OpenFileInput(filename)方法,得到FileInputStream,包裝成InputStreamReader,創(chuàng)建字符數(shù)組,然后調(diào)用read方法進行讀取,沒有沖刷緩沖區(qū)。記得關(guān)閉流,可將字符數(shù)組轉(zhuǎn)換為 String
//openFileInput()只有一個參數(shù),即需要讀取的文件名
FileInputStream fis = openFileInput(flieName);
//包裝成為InputStreamReader,可調(diào)用read方法
InputStreamReader isr =newInputStreamReader(fis,"UTF-8");
//創(chuàng)建字符數(shù)組,通過fis.available()獲取字符流中可用字符的長度
charinput[] =new char[fis.available()];
//將字符流讀入字符數(shù)組
isr.read(input);
isr.close();
fis.close();
//將字符數(shù)組轉(zhuǎn)為String
String text =newString(input);
//將string設(shè)置為TextView的內(nèi)容
tv.setText(text);
五、讀取外部儲存(external storage)的文件數(shù)據(jù)
外部儲存類似 sd card,一些設(shè)備將"internal" 與 "external" 都做成了不可卸載的內(nèi)置存儲,雖然如此,但是這一整塊還是從邏輯上有被劃分為"internal"與”external”.
Internal storage:
總是可用的
這里的文件默認(rèn)只能被我們的app所訪問。
當(dāng)用戶卸載app的時候,系統(tǒng)會把internal內(nèi)該app相關(guān)的文件都清除干凈。
Internal是我們在想確保不被用戶與其他app所訪問的最佳存儲區(qū)域。
External storage:
并不總是可用的,因為用戶有時會通過USB存儲模式掛載外部存儲器,當(dāng)取下掛載的這部分后,就無法對其進行訪問了。
是大家都可以訪問的,因此保存在這里的文件可能被其他程序訪問。
當(dāng)用戶卸載我們的app時,系統(tǒng)僅僅會刪除external根目錄(getExternalFilesDir())下的相關(guān)文件。
External是在不需要嚴(yán)格的訪問權(quán)限并且希望這些文件能夠被其他app所共享或者是允許用戶通過電腦訪問時的最佳存儲區(qū)域。盡管app是默認(rèn)被安裝到internal storage的,我們還是可以通過在程序的manifest文件中聲明android:installLocation屬性來指定程序安裝到external storage。
獲取external storage權(quán)限:寫入權(quán)限需要在Manifest文件中添加
讀取權(quán)限默認(rèn)目前默認(rèn)擁有,為確保準(zhǔn)確可以聲明
當(dāng)聲明擁有寫入外部儲存權(quán)限時,自動擁有讀取外部儲存的權(quán)限
使用Environment.getExternalStorageDirectory()獲取系統(tǒng)SD卡路徑
當(dāng)最小sdk小于23時,雖然在manifest文件中聲明了權(quán)限。應(yīng)用啟動時需要仍需要請求使用外部儲存。設(shè)置判斷是否請求權(quán)限與請求權(quán)限的函數(shù)
//判斷是否請求外部儲存權(quán)限
protected booleanshouldAskPermissions() {
return(Build.VERSION.SDK_INT> Build.VERSION_CODES.LOLLIPOP_MR1);
}
//當(dāng)最小sdk小于23時,請求外部儲存權(quán)限
@TargetApi(23)
protected voidaskPermissions() {
String[] permissions = {
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE"
};
intrequestCode =200;
requestPermissions(permissions,requestCode);
}
在onCreate函數(shù)中進行調(diào)用
External storage對其他應(yīng)用與用戶可訪問修改,其中文件分為兩類:public private
public:對其他用戶有用,應(yīng)用卸載時應(yīng)保留,例如下載的文件,拍攝的照片,保存的音樂
private:雖然技術(shù)上可以訪問,但對其他應(yīng)用無用,應(yīng)用卸載時自動刪除,主要為緩存
儲存在public時,使用getExternalStoragePublicDirectory()方法,參數(shù)為特定的文件類型
通過Environment.Directory獲得
//定義一個儲存在ExternalStorage的public的文件,參數(shù)必須為特定的文件類型:DIRECTORY_MUSIC 或者 DIRECTORY_PICTURES
Filesdcard= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
儲存在private時,使用getExternalStorageDirectory()方法,指定文件類型參數(shù)會儲存在private的參數(shù)文件夾下,不指定類型,儲存在private根目錄下
//在外部儲存private的根目錄下新建文件夾pictures
StringfilePath= Environment.getExternalStorageDirectory()+"/Pictures”;
獲取路徑后,按正常文件操作讀寫
寫入操作:
// 判斷設(shè)備sd卡是否存在
if(!sdcard.exists()){
Toast.makeText(getApplicationContext(),"sd卡不存在",Toast.LENGTH_SHORT).show();
return;
}
//文件不存在創(chuàng)建文件
if(!myFile.exists()){
try{
myFile.createNewFile();
}catch(IOException e) {
Log.e("文件創(chuàng)建失敗",e.getMessage());
e.printStackTrace();
}
//文件寫入操作
try{
FileOutputStream fos =newFileOutputStream(myFile);
OutputStreamWriter osw =newOutputStreamWriter(fos);
osw.write(et.getText().toString());
osw.flush();
fos.flush();
osw.close();
fos.close();
Toast.makeText(getApplicationContext(),"數(shù)據(jù)寫入成功",Toast.LENGTH_SHORT).show();
}catch(FileNotFoundException e) {
Log.e("文件沒找到",e.getMessage());
e.printStackTrace();
}catch(IOException e) {
Log.e("io錯誤",e.getMessage());
e.printStackTrace();
}
讀取操作:
// 判斷設(shè)備sd卡是否存在
if(!sdcard.exists()){
Toast.makeText(getApplicationContext(),"sd卡不存在",Toast.LENGTH_SHORT).show();
return;
}
//文件不存在創(chuàng)建文件
if(!myFile.exists()) {
try{
myFile.createNewFile();
}catch(IOException e) {
e.printStackTrace();
}
try{
FileInputStream fis =newFileInputStream(myFile);
InputStreamReader isr =newInputStreamReader(fis);
BufferedReader br =newBufferedReader(isr);
//StringBuilder儲存所有數(shù)據(jù)
StringBuilder strBuilder =newStringBuilder();
//臨時變量儲存每行數(shù)據(jù)
String line ="";
while((line = br.readLine()) !=null) {
//不為空,不斷追加
strBuilder.append(line);
}
br.close();
isr.close();
fis.close();
Toast.makeText(MainActivity.this,"數(shù)據(jù)讀取成功",Toast.LENGTH_SHORT).show();
tv.setText(strBuilder);
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}