一)文件存儲方式
通過java裏的文件讀取流和寫入流來對安卓的文件進行讀寫操作
安卓應用程序資源分類可以分爲兩大類,assets和res.其中res保存的文件大都會被編譯,並且會被賦予資源id,這樣我們可以在程序中通過id來訪問res類的資源,res按不同用途可以分爲anim,animator,color,drawable,layout,raw,menu,values,xml這九種。
1)讀取assets中的文件數據:assets類資源放在工程目錄的assets子目錄下,它裏面保存的是一些原始文件,可以以任何方式來進行組織,這些文件最終會原裝不動的打包在apk文件裏。
訪問assets文件資源通過getAssets().open()來打開文件名,注意inputStreamReader()裏面設置編碼格式爲utf-8,這樣統一編碼格式,防止亂碼出現。
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.get_assets:
try {
InputStream in=getResources().getAssets().open("info.txt");
InputStreamReader isr=new InputStreamReader(in,"utf-8");
BufferedReader bfr=new BufferedReader(isr);
System.out.println(bfr.readLine());
String s="";
while ((s=bfr.readLine())!=null){//讀取文件內容
System.out.println(s);
}
} catch (IOException e) {
e.printStackTrace();
}
break;
2)讀取raw文件:raw文件和assets文件一樣都是原封不動的打包在apk文件,不過raw會被賦予資源id,,這樣我們就可以在程序裏通過id來訪問他們。
通過openRawResource()傳入文件的id來訪問,傳入R.raw.filename
case R.id.get_raw:
// try {
// InputStream in = getResources().openRawResource(R.raw.inforaw);
// InputStreamReader isr = new InputStreamReader(in, "utf-8");
// BufferedReader brf = new BufferedReader(isr);
// String str = "";
// while ((str=brf.readLine())!=null){
// System.out.println(str);
// }
// } catch (UnsupportedEncodingException e) {
// e.printStackTrace();
// }catch (IOException e){
// e.printStackTrace();
// }
// break;
3)讀寫內部存儲的文件數據
存儲在內部還是外部
所有的Android設備均有兩個文件存儲區域:"internal" 與 "external" 。 這兩個名稱來自於早先的Android系統,當時大多設備都內置了不可變的內存(internal storage)及一個類似於SD card(external storage)這樣的可卸載的存儲部件。之後有一些設備將"internal" 與 "external" 都做成了不可卸載的內置存儲,雖然如此,但是這一整塊還是從邏輯上有被劃分爲"internal"與"external"的。只是現在不再以是否可卸載進行區分了。 下面列出了兩者的區別:
-
Internal storage:
- 總是可用的
- 這裏的文件默認只能被我們的app所訪問。
- 當用戶卸載app的時候,系統會把internal內該app相關的文件都清除乾淨。
- Internal是我們在想確保不被用戶與其他app所訪問的最佳存儲區域。
-
External storage:
- 並不總是可用的,因爲用戶有時會通過USB存儲模式掛載外部存儲器,當取下掛載的這部分後,就無法對其進行訪問了。
- 是大家都可以訪問的,因此保存在這裏的文件可能被其他程序訪問。
- 當用戶卸載我們的app時,系統僅僅會刪除external根目錄(getExternalFilesDir())下的相關文件。
- External是在不需要嚴格的訪問權限並且希望這些文件能夠被其他app所共享或者是允許用戶通過電腦訪問時的最佳存儲區域。
我們可以讀寫data目錄下的內部存儲數據,比如我們把在EditText裏面寫的文字寫入我們定義的一個filename,然後在data目錄下可以找到filename的文件裏存放着我們EditText的內容,並且可以讀取出來。
模式指定爲MODE_PRIVATE別的程序就不能訪問這個文件。
系統默認程序的安裝位置是內部,我們也可以在Manifest裏面修改。當程序卸載後,其內部文件也會被刪除。
我們的app的internal storage 目錄以app的包名作爲標識存放在Android文件系統的特定目錄下[data/data/com.example.xx]。 從技術上講,如果文件被設置爲可讀的,那麼其他app就可以讀取該internal文件。然而,其他app需要知道包名與文件名。若沒有設置爲可讀或者可寫,其他app是沒有辦法讀寫的。因此我們只要使用了MODE_PRIVATE ,那麼這些文件就不可能被其他app所訪問。
case R.id.get_write:
try {
FileOutputStream fileOutputStream=openFileOutput(filename, Context.MODE_PRIVATE);
OutputStreamWriter outputStreamWriter=new OutputStreamWriter(fileOutputStream,"utf-8");
outputStreamWriter.write(write.getText().toString());
outputStreamWriter.flush();
fileOutputStream.flush();
outputStreamWriter.close();
fileOutputStream.close();
Toast.makeText(MainActivity.this,"寫入完成",Toast.LENGTH_SHORT).show();
} catch (FileNotFoundException e) {
}catch (UnsupportedEncodingException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
break;
case R.id.read:
try {
FileInputStream fileInputStream=openFileInput(filename);
InputStreamReader inputStreamReader=new InputStreamReader(fileInputStream,"utf-8");
char[] input=new char[fileInputStream.available()];//文件長度設置爲字符數組長度
inputStreamReader.read(input);
inputStreamReader.close();
fileInputStream.close();
String str=new String(input); //字符數組轉換爲字符串
show.setText(str);
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (UnsupportedEncodingException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
break;
4)讀取外部存儲的文件數據
寫數據到外部存儲,需要聲明權限(在android4.4之後外部存儲的讀寫都不再需要聲明權限)
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
如果聲明瞭寫權限,那麼程序默認有讀取的權限。
否則如果程序只需要讀取的權限,我們應該聲明讀取權限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
因爲存儲在外部的數據有可能發生變化,比如sd卡拔掉,所以在讀寫之前我們應該先對其可用性狀態進行檢查,使用getExternalStorageState()進行檢查,如果返回值是MEDIA_MOUNTED,那麼可以進行讀寫
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
如果我們只需要對程序的是否可讀的狀態進行檢測,那麼:
/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
存儲在外部的數據分爲public 和private兩種,public files在程序卸載時應該保留,比如被程序拍攝的照片或者下載的文件。private files在程序卸載的時候應該刪除,因爲這些緩存文件對其他程序來說並沒有任何意義。
以public 形式向外部存儲寫入數據:getExternalStoragePublicDirectory()來構建一個File對象表示存儲在External Storage目錄,其包含一個指定文件類型的參數,以便於與其他public 文件區別,比如DIRECTORY_MUSIC和DIRECTORY_PICTURES
public File getAlbumStorageDir(String albumName) {
// Get the directory for the user's public pictures directory.
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}
以private形式存儲,getExternalFileDir來獲取File對象,表示存儲在app下的參數文件夾下,比如下面例子的(albumName)。這個文件夾會在程序卸載的時候刪除。
public File getAlbumStorageDir(Context context, String albumName) {
// Get the directory for the app's private pictures directory.
File file = new File(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, "Directory not created");
}
return file;
}
這樣將文件保存在外部存儲之後,就可以進行讀取的操作。
二)SharedPreference的使用
SharedPreference是一種輕型的數據存儲形式,使用鍵值對來讀寫,並且通過SharedPrefrence.Editor來存儲。
其存儲位置在/data/data/com.xxxxxxx(package name)/shared-prefs目錄。
我們可以通過getSharedPreFerences()和getPreFerences()來創建Shared Preferences文件,前者需要在參數裏設置一個文件名,並且通過Context來執行;後者不需要設置文件名,而且是通過Activity來執行
private SharedPreferences preference=getPreferences(Activity.MODE_PRIVATE);
private Editor editor=preference.edit();
sharedPreferences()的讀和寫操作:
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.write:
editor.putString(KEY, input.getText().toString());
if (editor.commit()) {
Toast.makeText(MainActivity.this, "寫入數據成功",Toast.LENGTH_SHORT).show();
}
break;
case R.id.read:
String data=preference.getString(KEY, "數據不存在");
Toast.makeText(MainActivity.this,data, Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}