我有一臺中興的Android手機,型號是 ZTE U930HD,手機沒有插入外置SD卡(也就是Micro SD Card,原名Trans-flash Card(TF卡),2004年正式改名爲Micro SD Card),可是機身自帶了一個內置存儲卡(也就是eMMC存儲,大小爲2G)。
我把這個手機用數據線插到電腦上,也會看到盤符,經過安裝「R.E 管理器」等文件管理應用,也能夠管理文件,而且能看到該存儲的掛載目錄是:/mnt/sdcard2
可是,
我打印 Environment.getExternalStorageState(),卻返回 」removed「;
這是怎麼回事?明明手機自己帶着內置SD卡,卻爲什麼提示這麼一個信息?
我又試着去打印了Environment.getExternalStorageDirectory(),返回:「/mnt/sdcard」
看起來能夠解釋了,在我這個中興手機上,調用Environment.getExternalStorageDirectory(),返回的存儲目錄並非系統內置的SD卡目錄。
我又換了一個 Sony L39u,一個 MOTO G,調用Environment.getExternalStorageDirectory()返回的目錄就是系統內置的SD卡目錄。
不一樣的設備上,調用getExternalStorageDirectory()返回值卻不同。查詢了Android的文檔,才找到緣由,原來這個方法返回的是當前設備廠商所認爲的「外部存儲」,有可能返回外置的SD卡目錄(Micro SD Card),也可能返回內置的存儲目(eMMC)。
總結一下:
一部分手機將eMMC存儲掛載到 /mnt/external_sd 、/mnt/sdcard2 等節點,而將外置的SD卡掛載到 Environment.getExternalStorageDirectory()這個結點。
此時,調用Environment.getExternalStorageDirectory(),則返回外置的SD的路徑。
而另外一部分手機直接將eMMC存儲掛載在Environment.getExternalStorageDirectory()這個節點,而將真正的外置SD卡掛載到/mnt/external_sd、/mnt/sdcard2 等節點。
此時,調用Environment.getExternalStorageDirectory(),則返回內置的SD的路徑。
至此就能解釋爲都是無外置SD卡的狀況下,在中興手機上,調用
打印 Environment.getExternalStorageState(),卻返回 」removed「,在索尼、MOTO G上就返回:「mounted」
緣由已經知道了,但是如何在無外置SD卡的時候,獲取到這個內置eMMC存儲的具體路徑呢?
好比,我這個中興手機,既然使用 Environment.getExternalStorageDirectory() 獲取到的是外置SD卡路徑,可是我又沒有插入SD卡,這個時候我想使用內置的eMMC存儲來存儲一些程序中用到的數據,我怎麼去獲取這個eMMC存儲的路徑呢?
答案是:經過掃描系統文件"system/etc/vold.fstab」來實現。
"system/etc/vold.fstab」 只是一個簡單的配置文件,它描述了Android的掛載點信息。
咱們能夠遍歷這個文件來獲取全部的掛載點:java
/**
* 遍歷 "system/etc/vold.fstab」 文件,獲取所有的Android的掛載點信息
*
* @return
*/
private
static
ArrayList<String> getDevMountList() {
String[] toSearch = readFile(
"/etc/vold.fstab"
).split(
" "
);
ArrayList<String> out =
new
ArrayList<String>();
for
(
int
i =
0
; i < toSearch.length; i++) {
if
(toSearch[i].contains(
"dev_mount"
)) {
if
(
new
File(toSearch[i +
2
]).exists()) {
out.add(toSearch[i +
2
]);
}
}
}
return
out;
}
linux
/**ide
* read filespa
* code
* @param filePathorm
* @param charsetName The name of a supported {@link java.nio.charset.Charset </code>charset<code>}ci
* @return if file not exist, return null, else return content of filerem
* @throws RuntimeException if an error occurs while operator BufferedReader文檔
*/get
public static String readFile(String filePath) {
String fileContent = "";
File file = new File(filePath);
if (file == null || !file.isFile()) {
return null;
}
BufferedReader reader = null;
try {
InputStreamReader is = new InputStreamReader(new FileInputStream(file));
reader = new BufferedReader(is);
String line = null;
int i = 0;
while ((line = reader.readLine()) != null) {
fileContent += line + " ";
}
reader.close();
return fileContent;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return fileContent;
}
以後,當 Environment.getExternalStorageState()返回「removed」的時候(即,當沒有掛載外置SD卡的時候),經過getDevMountList()方法獲取一個list,這個list中能夠進行寫操做的那個就是系統自帶的eMMC存儲目錄了。
判斷邏輯:
/**
* 獲取擴展SD卡存儲目錄
*
* 若是有外接的SD卡,而且已掛載,則返回這個外置SD卡目錄
* 不然:返回內置SD卡目錄
*
* @return
*/
public
static
String getExternalSdCardPath() {
if
(SDCardUtils.isMounted()) {
File sdCardFile =
new
File(Environment.getExternalStorageDirectory().getAbsolutePath());
return
sdCardFile.getAbsolutePath();
}
String path =
null
;
File sdCardFile =
null
;
ArrayList<String> devMountList = getDevMountList();
for
(String devMount : devMountList) {
File file =
new
File(devMount);
if
(file.isDirectory() && file.canWrite()) {
path = file.getAbsolutePath();
String timeStamp =
new
SimpleDateFormat(
"ddMMyyyy_HHmmss"
).format(
new
Date());
File testWritable =
new
File(path,
"test_"
+ timeStamp);
if
(testWritable.mkdirs()) {
testWritable.delete();
}
else
{
path =
null
;
}
}
}
if
(path !=
null
) {
sdCardFile =
new
File(path);
return
sdCardFile.getAbsolutePath();
}
return
null
;
}
但有的手機設備中沒法用getExternalSdCardPath()獲得內置存儲的路徑,在system/etc/vold.fstab文件裏並無列明,如三星手機。這時須要經過使用linux的 mount命令來實現讀取路徑。
/*
得到外部內置存在路徑
經過執行mount命令來得到內置存儲的路徑
*/
public String getExterPath(){
//獲得路徑
String sdcard_path="";
try {
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("mount");
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
String line;
BufferedReader br = new BufferedReader(isr);
while ((line = br.readLine()) != null) {
if (line.contains("secure")) continue;
if (line.contains("asec")) continue;
if (line.contains("fat")) {
String columns[] = line.split(" ");
if (columns != null && columns.length > 1) {
sdcard_path = sdcard_path.concat(columns[1]);
}
} else if (line.contains("fuse")) {
String columns[] = line.split(" ");
if (columns != null && columns.length > 1) {
sdcard_path = sdcard_path.concat(columns[1] );
}
}
}
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sdcard_path;
}