由于Android使用的文件系統(tǒng)是基于Linux的文件系統(tǒng),這就允許程序開發(fā)人員建立和訪問程序自身的私有文件,也可以訪問保存在資源目錄中的原始文件和XML文件,還可以保存文件在SD卡等外部存儲(chǔ)設(shè)備中。
本文先介紹下內(nèi)部存儲(chǔ)
Android系統(tǒng)允許應(yīng)用程序創(chuàng)建僅能夠自身訪問的私有文件,文件保存在設(shè)備的內(nèi)部存儲(chǔ)器上的/data/data/<package name>/files目錄中。和傳統(tǒng)的Java中實(shí)現(xiàn)I/O的程序類似,在Android中,其提供了openFileInput 和 openFileOutput 方法讀取設(shè)備上的文件。
1.openFileOutput()
openFileOutput()方法打開的應(yīng)用程序私有文件,為寫入數(shù)據(jù)做準(zhǔn)備。在默認(rèn)情況下,寫入的時(shí)候會(huì)覆蓋原文件內(nèi)容,如果想把新寫入的內(nèi)容附加到原文件內(nèi)容后,則可以指定其mode為Context.MODE_APPEND;如果指定的打開文件不存在時(shí),則創(chuàng)建一個(gè)新的文件。默認(rèn)情況下,使用openFileOutput方法創(chuàng)建的文件只能被其調(diào)用的應(yīng)用使用,其他應(yīng)用無法讀取這個(gè)文件。
openFileOutput()方法的語法格式如下:
代碼清單7-10 openFileOutput()
public FileOutputStream openFileOutput(String name, int mode)
其中,第1個(gè)參數(shù)是文件名稱,這個(gè)參數(shù)不可以包含描述路徑的斜杠,也就是說,它并不允許我們?nèi)バ薷谋4嫖募穆窂;?個(gè)參數(shù)是操作模式;方法的返回值是FileOutputStream類型。
關(guān)于第2個(gè)參數(shù)——操作模式來講,Android系統(tǒng)支持4種文件操作模式,具體如表7-1所示。
表7-1 Android系統(tǒng)支持4種文件操作模式
模式 |
說明 |
MODE_PRIVATE |
私有模式,缺陷模式,文件僅能夠被文件創(chuàng)建程序訪問,或具有相同UID的程序訪問 |
MODE_APPEND |
追加模式,如果文件已經(jīng)存在,則在文件的結(jié)尾處添加新數(shù)據(jù) |
MODE_WORLD_READABLE |
全局讀模式,允許任何程序讀取私有文件 |
MODE_WORLD_WRITEABLE |
全局寫模式,允許任何程序?qū)懭胨接形募?/td>
|
使用openFileOutput()方法建立新文件的示例代碼如代碼清單7-11所示。
代碼清單7-11 openFileOutput()建立新文件
//建立文件的名稱fileDemo.txt
String FILE_NAME = "fileDemo.txt";
//使用openFileOutput()方法以私有模式建立文件
FileOutputStream fos = openFileOutput
(FILE_NAME,Context.MODE_PRIVATE);
String text = "Some data";
//將數(shù)據(jù)寫入文件
fos.write(text.getBytes());
//將所有剩余的數(shù)據(jù)寫入文件
fos.flush();
//關(guān)閉FileOutputStream
fos.close();
注意:
為了提高文件系統(tǒng)的性能,一般調(diào)用write()函數(shù)時(shí),如果寫入的數(shù)據(jù)量較小,系統(tǒng)會(huì)把數(shù)據(jù)保存在數(shù)據(jù)緩沖區(qū)中,等數(shù)據(jù)量累積到一定程度時(shí)再一次性地寫入文件中。由此可知,在調(diào)用close()函數(shù)關(guān)閉文件前,務(wù)必要調(diào)用flush()函數(shù),將緩沖區(qū)內(nèi)所有的數(shù)據(jù)寫入文件。
2.openFileInput()
openFileInput()方法打開應(yīng)用程序私有文件為從其中讀取數(shù)據(jù)而做準(zhǔn)備。openFileInput()方法的語法格式如代碼清單7-12所示。
代碼清單7-12 openFileInput()
public FileInputStream openFileInput (String name)
第1個(gè)參數(shù)是文件名稱,同樣不允許包含描述路徑的斜杠。
使用openFileInput ()方法打開已有文件的示例代碼如代碼清單7-13所示。
代碼清單7-13 openFileInput()打開已有文件
String FILE_NAME = "fileDemo.txt";
FileInputStream fis = openFileInput(FILE_NAME);
byte[] readBytes = new byte[fis.available()];
while(fis.read(readBytes) != -1){
}
上面的兩部分代碼在實(shí)際使用過程中會(huì)遇到錯(cuò)誤提示,在實(shí)際使用過程中,應(yīng)該使用try/catch捕獲可能產(chǎn)生的異常來避免因?yàn)槲募僮饔龅降母鞣N問題而導(dǎo)致的操作失敗。
InternalFileDemo示例用來演示在內(nèi)部存儲(chǔ)器上進(jìn)行文件寫入和讀取,示例的用戶界面如圖7-3所示。

圖7-3 InternalFileDemo示例用戶界面圖
InternalFileDemo示例的核心代碼如代碼清單7-14所示。
代碼清單7-14 InternalFileDemo示例的核心代碼
OnClickListener writeButtonListener = new OnClickListener() {
@Override
public void onClick(View v) {
FileOutputStream fos = null;
try {
if (appendBox.isChecked()){
fos = openFileOutput(FILE_NAME,Context.MODE_APPEND);
}else {
fos = openFileOutput(FILE_NAME,Context.MODE_PRIVATE);
}
String text = entryText.getText().toString();
fos.write(text.getBytes());
labelView.setText("文件寫入成功,寫入長度:"+text.length());
entryText.setText("");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
finally{
if (fos != null){
try {
fos.flush();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
};
OnClickListener readButtonListener = new OnClickListener() {
@Override
public void onClick(View v) {
displayView.setText("");
FileInputStream fis = null;
try {
fis = openFileInput(FILE_NAME);
if (fis.available() == 0){
return;
}
byte[] readBytes = new byte[fis.available()];
while(fis.read(readBytes) != -1){
}
String text = new String(readBytes);
displayView.setText(text);
labelView.setText("文件讀取成功,文件長度:"+text.length());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
};
程序運(yùn)行后,可以在/data/data/cn.com.farsight.InternalFileDemo/files/目錄下,找到新建立的fileDemo.txt文件: fileDemo.txt從文件權(quán)限上進(jìn)行分析,“-rw-rw---”表明文件僅允許文件創(chuàng)建者和同組用戶讀/寫,其他用戶無權(quán)使用;文件內(nèi)保存的數(shù)據(jù)為“Some data”,其大小為9個(gè)字節(jié)。