外部存儲
在以前的文章中,我們介紹了使用Activity的openFileOutput()方法來保存文件,其保存的文件是存放在手機空間上,而一般手機的存儲空間不是很大,存放些小文件還行,如果要存放像視頻這樣的大文件就存在困難。對于像視頻這樣的大文件,可以把它存放在SDCard。
SD卡(Secure Digital Memory Card)是Android的外部存儲設備,是一種廣泛使用于數(shù)碼設備上的記憶卡。然而,SD卡中的文件為全局可訪問的,而且可以被用戶操作,因此,SD卡適用于保存大尺寸的文件或者是一些無須設置訪問權限的文件,可以保存錄制的大容量的視頻文件和音頻文件等。
Android系統(tǒng)提供了對SD卡便捷地訪問方法。Android模擬器支持SD卡,可以使用以下兩種方式來創(chuàng)建SD卡。
(1)使用<Android SDK>/tools目錄下的mksdcard工具創(chuàng)建SD卡映像文件,命令如代碼清單7-15所示。
代碼清單7-15 創(chuàng)建SD卡映像文件
mksdcard -l SDCARD 256M E:\android\sdcard_file
該命令中,第1個參數(shù)-1表示后面的字符串是SD卡的標簽,這個新建立的SD卡的標簽是SDCARD;第2個參數(shù)256M表示SD卡的容量是256兆;后一個參數(shù)表示SD卡映像文件的保存位置,上面的命令將映像保存在E:\android目錄下sdcard_file文件中。在CMD中執(zhí)行該命令后,則可在所指定的目錄中找到生產(chǎn)的SD卡映像文件。
如果希望Android模擬器啟動時能夠自動加載指定的SD卡,還需要在模擬器的“運行設置”(Run Configurations)中添加SD卡加載命令,而SD卡加載命令中只要指明映像文件位置即可。SD卡加載命令如圖7-4所示。

圖7-4 SD卡加載命令
那么如何測試SD卡映像是否正確加載呢?在模擬器啟動后,使用FileExplorer向SD卡中隨意上傳一個文件,如果文件上傳成功,則表明SD卡映像已經(jīng)成功加載。
(2)在創(chuàng)建模擬器Android Virtual Device(AVD)時,自定義SD卡的大小,由系統(tǒng)來完成模擬器虛擬SD卡的創(chuàng)建,如圖7-5所示。

圖7-5 創(chuàng)建模擬器時選擇SD卡大小
創(chuàng)建完成后,啟動該模擬器,打開Eclipse的DDMS→File→Explorer,可以看到目錄結(jié)構(gòu)。
在加載SD卡后,需要通過編程來訪問SD卡:首先需要在使用外部儲存之前必須調(diào)用getExternalStorageState()方法來檢查存儲媒介是否可用來檢測系統(tǒng)的/sdcard目錄是否可用,如果不可用,則說明設備中的SD卡已經(jīng)被移除或者被掛載到一臺電腦上、遺失、只讀或處于其他狀態(tài);在Android模擬器則表明SD卡映像沒有被正確加載等;如果可用,則直接通過使用標準的Java.io.File類進行訪問,將數(shù)據(jù)保存在SD卡。
檢測SD卡是否可用的代碼如代碼清單7-16所示。
代碼清單7-16 檢驗SD卡是否可用
boolean mExternalStorageAvailable = false;
boolean mExternalStorageWriteable = false;
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
// 對SD卡上的存儲可以進行讀/寫操作
mExternalStorageAvailable = mExternalStorageWriteable = true;
} else
if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state))
{
//對SD卡上的存儲可以進行讀操作
mExternalStorageAvailable = true;
mExternalStorageWriteable = false;
} else {
//對SD卡上的存儲不可用
mExternalStorageAvailable = mExternalStorageWriteable = false;
}
下面通過SDcardFileDemo示例說明如何將數(shù)據(jù)保存在SD卡。圖7-6所示DcardFileDemo示例的用戶界面。

圖7-6 SDcardFileDemo示例的用戶界面
在圖7-6所示界面中,通過“生產(chǎn)隨機數(shù)列”按鈕生產(chǎn)10個隨機小數(shù);通過“寫入SD卡”按鈕將生產(chǎn)的數(shù)據(jù)保存在SD卡的目錄下。SDcardFileDemo示例運行后,在每次單擊“寫入SD卡”按鈕后,都會在SD卡中生產(chǎn)一個新文件,文件名各不相同。
SDcardFileDemo示例的核心代碼如代碼清單7-17所示。
代碼清單7-17 SDcardFileDemo示例的核心代碼
private static String randomNumbersString = "";
OnClickListener writeButtonListener = new OnClickListener() {
@Override
public void onClick(View v) {
String fileName = "SdcardFile-"+System.currentTimeMillis()+".txt";
File dir = new File("/sdcard/");
if (dir.exists() && dir.canWrite()) {
File newFile = new File(dir.getAbsolutePath() + "/" + fileName);
FileOutputStream fos = null;
try {
newFile.createNewFile();
if (newFile.exists() && newFile.canWrite()) {
fos = new FileOutputStream(newFile);
fos.write(randomNumbersString.getBytes());
TextView labelView = (TextView)findViewById(R.id.label);
labelView.setText(fileName + "文件寫入SD卡");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try{
fos.flush();
fos.close();
}
catch (IOException e) { }
}
}
}
}
};
由上述代碼可以看出,SDcardFileDemo示例與InternalFileDemo示例的核心代碼比較相似,但SDcardFileDemo示例與InternalFileDemo示例也有不同之處:第7行代碼中添加了/sdcard目錄存在性檢查;第8行代碼使用“絕對目錄+文件名”的形式表示新建立的文件;第12行代碼寫入文件前對文件存在性和可寫入性進行檢查;第5行代碼為了保證在SD卡中多次寫入時文件名不會重復,在文件名中使用了唯一且不重復的標識,這個標識通過調(diào)用System.currentTimeMillis()方法獲得,表示從1970年00:00:00到當前所經(jīng)過的毫秒數(shù)。