安卓專案實戰之關於獲取SD卡指定路徑和檔案的講解
前言
當我們將手機連線到電腦上時,我們發現在SD卡的根目錄下生成了成百上千的由各種應用程式建立的資料夾,導致我們也不知道哪個資料夾是用來幹嘛的,這正因為這樣安卓開發人員經常受到使用者的吐槽。
的確作為一個安卓開發者,我們的確不應該將我們應用的資料直接存到SD卡的根目錄下,這樣當手機安裝了大量的app時,SD卡根目錄會迅速變得雜亂不堪。
獲取SD卡的根目錄(/storage/sdcard0):
File file = Environment.getExternalStorageDirectory();
為了方便管理,我們一般將app中的檔案分為兩種:app私有檔案和app公共檔案
接下來我們將針對這兩類檔案分別應該存放在什麼樣的路徑下做具體的講解。
app公共檔案
app公共檔案指的是那些不依賴於某特定app的檔案,例如照片等。
這類檔案當我們刪除應用之後,還應該保留在手機上的,不應該隨著刪除應用而被刪除掉。
對於這類檔案,Android給我們提供了特定的目錄,即SD卡的九大公有目錄,我們可以通過Environment.getExternalStoragePublicDirectory(String type)來進行獲取,這些目錄的type都是以DIRECTORY開頭的,例如:DIRECTORY_MUSIC , DIRECTORY_PICTURES.
使用如下程式碼訪問:
File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
SD卡內建的九大公有目錄一覽表:
方法 | 路徑 | 用途 |
---|---|---|
Environment.DIRECTORY_ALARMS | /storage/sdcard0/Alarms | 警報的鈴聲 |
Environment.DIRECTORY_DCIM | /storage/sdcard0/DCIM | 相機拍攝的圖片和視訊儲存的位置 |
Environment.DIRECTORY_DOWNLOADS | /storage/sdcard0/Download | 下載檔案儲存的位置 |
Environment.DIRECTORY_MOVIES | /storage/sdcard0/Movies | 電影儲存的位置 |
Environment.DIRECTORY_MUSIC | /storage/sdcard0/Music | 音樂儲存的位置 |
Environment.DIRECTORY_NOTIFICATIONS | /storage/sdcard0/Notifications | 通知音儲存的位置 |
Environment.DIRECTORY_PICTURES | /storage/sdcard0/Pictures | 下載的圖片儲存的位置 |
Environment.DIRECTORY_PODCASTS | /storage/sdcard0/Podcasts | 用於儲存podcast(部落格)的音訊檔案 |
Environment.DIRECTORY_RINGTONES | /storage/sdcard0/Ringtones | 儲存鈴聲的位置 |
APP私有檔案
這類檔案應該是隨著app刪除而一起刪除的,它們可以被儲存在兩個地方:internal storage 和 external storage 。 internal storage就是手機自帶的一塊儲存區域,通常很小;external storage就是通常所說的SD卡,通常很大,有16GB,32GB等。
internal storage很小,所以你就應該很正確的使用它,因為SD卡有可能會被使用者卸下,換成新的,所以SD卡不是任何時間都可用的,因此我們必須將一些重要的資料庫檔案以及一些使用者配置檔案存放在internal storage中。將一些大的圖片或檔案等快取放到external storage中。
儲存在internal storage
目錄為data/data/< package name >/files/
訪問方法為:
File filesDir = getFilesDir();
Log.i(TAG,"file_dir="+filesDir);
眾所周知我們app中建立的SharedPreference配置檔案預設就是儲存在該目錄下的。
Android提供了兩種方法來快捷的訪問內部儲存目錄:getCacheDir()和getFilesDir()方法:
1,getCacheDir()方法用於獲取/data/data/< package name>/cache目錄
2,getFilesDir()方法用於獲取/data/data/< package name>/file目錄
儲存在external storage
對於需要儲存在SD卡上的私有檔案我們不應該直接存在SD卡的根目錄下,而應該存在mnt/sdcard/Android/data/< package name >/files/…這個目錄下。這類檔案應該隨著App的刪除而一起刪除。例如一種格式的電子書,只有該app才可以開啟,如果使用者刪除了該app,那麼留下來的電子書就成為了一種無法開啟的垃圾檔案,所以應該隨著該app一起刪除掉。
獲得這個路徑的方法:
File externalFilesDir = getExternalFilesDir(null);
Log.i(TAG, "externalFileDir = "+externalFilesDir);
我們注意到上面的getExternalFilesDir(null)引數傳入的為null,這樣預設訪問的是files資料夾,我們可以指定子資料夾:
File externalFilesDir = getExternalFilesDir("Caches");
Log.i(TAG, "externalFileDir = "+externalFilesDir);
SD卡操作時必須新增許可權
① SDCard中建立與刪除檔案許可權
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
② 從SDCard中讀取檔案的許可權
< uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
③ 向SDCard中寫入檔案的許可權
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
判斷SD卡是否可用
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
// SD卡可用
} else {
Toast.makeText(MainActivity.this,"SD卡不可用,請檢查SD卡",Toast.LENGTH_LONG).show();
}
建立File物件的三種方式:
File物件代表一個具體的檔案或者一個資料夾,其構造方法有三個:
// 通過將給定路徑名字串轉換成抽象路徑名來建立一個新 File 例項
File(String pathname)
// 根據 parent 路徑名字串和 child 路徑名字串建立一個新 File 例項
File(String parent, String child)
// 通過給定的父抽象路徑名和子路徑名字串建立一個新的File例項
File(File parent, String child);
如:
// 建立一個資料夾
new File(Environment.getExternalStorageDirectory(),"test");
// 建立一個檔案
new File(Environment.getExternalStorageDirectory(),"test.apk");
獲取SD卡的可用空間並顯示在介面上
public void getSize(){
myTextView.setText("");
myBar.setProgress(0);
//判斷是否有插入儲存卡
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
File path =Environment.getExternalStorageDirectory();
//取得sdcard檔案路徑
StatFs statfs=new StatFs(path.getPath());
//獲取block的SIZE
long blocSize=statfs.getBlockSize();
//獲取BLOCK數量
long totalBlocks=statfs.getBlockCount();
//己使用的Block的數量
long availaBlock=statfs.getAvailableBlocks();
String[] total=filesize(totalBlocks*blocSize);
String[] availale=filesize(availaBlock*blocSize);
//設定進度條的最大值
int maxValue=Integer.parseInt(availale[0]);
myBar.getMax()/Integer.parseInt(total[0]);
myBar.setProgress(maxValue);
String Text="總共:"+total[0]+total[1]+"/n"
+"可用:"+availale[0]+availale[1];
myTextView.setText(Text);
}else
if(Environment.getExternalStorageState().equals(Environment.MEDIA_REMOVED)){
Toast.makeText(getStorageActivity.this, "沒有sdCard",1000).show();
}
}
//返回陣列,下標1代表大小,下標2代表單位 KB/MB
String[] filesize(long size){
String str="";
if(size>=1024){
str="KB";
size/=1024;
if(size>=1024){
str="MB";
size/=1024;
}
}
DecimalFormat formatter=new DecimalFormat();
formatter.setGroupingSize(3);
String result[] =new String[2];
result[0]=formatter.format(size);
result[1]=str;
return result;
}