我們先來(lái)考慮這樣一個(gè)問(wèn)題:
打開(kāi)手機設置,選擇應用管理,選擇任意一個(gè)App,然后你會(huì )看到兩個(gè)按鈕,一個(gè)是清除緩存,另一個(gè)是清除數據,那么當我們點(diǎn)擊清除緩存的時(shí)候清除的是哪里的數據?當我們點(diǎn)擊清除數據的時(shí)候又是清除的哪里的數據?讀完本文相信你會(huì )有答案。
在android開(kāi)發(fā)中我們常常聽(tīng)到這樣幾個(gè)概念,內存,內部存儲,外部存儲,很多人常常將這三個(gè)東西搞混,那么我們今天就先來(lái)詳細說(shuō)說(shuō)這三個(gè)東西是怎么回事?
內存,我們在英文中稱(chēng)作memory,內部存儲,我們稱(chēng)為InternalStorage,外部存儲我們稱(chēng)為ExternalStorage,這在英文中本不會(huì )產(chǎn)生歧義,但是當我們翻譯為中文之后,前兩個(gè)都簡(jiǎn)稱(chēng)為內存,于是,混了。
那么究竟什么是內部存儲什么是外部存儲呢?
首先我們打開(kāi)DDMS,有一個(gè)File Explorer,如下:
這里有三個(gè)文件夾需要我們重視,一個(gè)是data,一個(gè)是mnt,一個(gè)是storage,我們下面就詳細說(shuō)說(shuō)這三個(gè)文件夾。
1.內部存儲
data文件夾就是我們常說(shuō)的內部存儲,當我們打開(kāi)data文件夾之后(沒(méi)有root的手機不能打開(kāi)該文件夾),里邊有兩個(gè)文件夾值得我們關(guān)注,如下:
一個(gè)文件夾是app文件夾,還有一個(gè)文件夾就是data文件夾,app文件夾里存放著(zhù)我們所有安裝的app的apk文件,其實(shí),當我們調試一個(gè)app的時(shí)候,可以看到控制臺輸出的內容,有一項是uploading .....就是上傳我們的apk到這個(gè)文件夾,上傳成功之后才開(kāi)始安裝。另一個(gè)重要的文件夾就是data文件夾了,這個(gè)文件夾里邊都是一些包名,打開(kāi)這些包名之后我們會(huì )看到這樣的一些文件:
1.data/data/包名/shared_prefs
2.data/data/包名/databases
3.data/data/包名/files
4.data/data/包名/cache
如果打開(kāi)過(guò)data文件,應該都知道這些文件夾是干什么用的,我們在使用sharedPreferenced的時(shí)候,將數據持久化存儲于本地,其實(shí)就是存在這個(gè)文件中的xml文件里,我們App里邊的數據庫文件就存儲于databases文件夾中,還有我們的普通數據存儲在files中,緩存文件存儲在cache文件夾中,存儲在這里的文件我們都稱(chēng)之為內部存儲。
2.外部存儲
外部存儲才是我們平時(shí)操作最多的,外部存儲一般就是我們上面看到的storage文件夾,當然也有可能是mnt文件夾,這個(gè)不同廠(chǎng)家有可能不一樣。
一般來(lái)說(shuō),在storage文件夾中有一個(gè)sdcard文件夾,這個(gè)文件夾中的文件又分為兩類(lèi),一類(lèi)是公有目錄,還有一類(lèi)是私有目錄,其中的公有目錄有九大類(lèi),比如DCIM、DOWNLOAD等這種系統為我們創(chuàng )建的文件夾,私有目錄就是Android這個(gè)文件夾,這個(gè)文件夾打開(kāi)之后里邊有一個(gè)data文件夾,打開(kāi)這個(gè)data文件夾,里邊有許多包名組成的文件夾。
說(shuō)到這里,我想大家應該已經(jīng)可以分清楚什么是內部存儲什么是外部存儲了吧?好,分清楚之后我們就要看看怎么來(lái)操作內部存儲和外部存儲了。
3.操作存儲空間
首先,經(jīng)過(guò)上面的分析,大家已經(jīng)明白了,什么是內部存儲,什么是外部存儲,以及這兩種存儲方式分別存儲在什么位置,一般來(lái)說(shuō),我們不會(huì )自己去操作內部存儲空間,沒(méi)有root權限的話(huà),我們也沒(méi)法操作內部存儲空間,事實(shí)上內部存儲主要是由系統來(lái)維護的。不過(guò)在代碼中我們是可以訪(fǎng)問(wèn)到這個(gè)文件夾的。由于內部存儲空間有限,在開(kāi)發(fā)中我們一般都是操作外部存儲空間,Google官方建議我們App的數據應該存儲在外部存儲的私有目錄中該App的包名下,這樣當用戶(hù)卸載掉App之后,相關(guān)的數據會(huì )一并刪除,如果你直接在/storage/sdcard目錄下創(chuàng )建了一個(gè)應用的文件夾,那么當你刪除應用的時(shí)候,這個(gè)文件夾就不會(huì )被刪除。
經(jīng)過(guò)以上的介紹,我們可以總結出下面一個(gè)表格:
一目了然,什么是內部存儲,什么是外部存儲。
如果按照路徑的特征,我們又可以將文件存儲的路徑分為兩大類(lèi),一類(lèi)是路徑中含有包名的,一類(lèi)是路徑中不含有包名的,含有包名的路徑,因為和某個(gè)App有關(guān),所以對這些文件夾的訪(fǎng)問(wèn)都是調用Context里邊的方法,而不含有包名的路徑,和某一個(gè)App無(wú)關(guān),我們可以通過(guò)Environment中的方法來(lái)訪(fǎng)問(wèn)。如下圖:
大家看到,有包名的路徑我們都是調用Context中的方法來(lái)獲得,沒(méi)有包名的路徑,我們直接調用Environment中的方法獲得,那么其中有兩個(gè)方法需要傳入一個(gè)String類(lèi)型的參數,這個(gè)參數我們使用了Environment中的常量,參數的意思是我們要訪(fǎng)問(wèn)這個(gè)路徑下的哪個(gè)文件夾,比如getExternalFilesDir方法,我們看看它的源碼:
- /**
- *
- * @param type The type of files directory to return. May be null for
- * the root of the files directory or one of
- * the following Environment constants for a subdirectory:
- * {@link android.os.Environment#DIRECTORY_MUSIC},
- * {@link android.os.Environment#DIRECTORY_PODCASTS},
- * {@link android.os.Environment#DIRECTORY_RINGTONES},
- * {@link android.os.Environment#DIRECTORY_ALARMS},
- * {@link android.os.Environment#DIRECTORY_NOTIFICATIONS},
- * {@link android.os.Environment#DIRECTORY_PICTURES}, or
- * {@link android.os.Environment#DIRECTORY_MOVIES}.
- *
- * @return The path of the directory holding application files
- * on external storage. Returns null if external storage is not currently
- * mounted so it could not ensure the path exists; you will need to call
- * this method again when it is available.
- *
- * @see #getFilesDir
- * @see android.os.Environment#getExternalStoragePublicDirectory
- */
- @Nullable
- public abstract File getExternalFilesDir(@Nullable String type);
它的注釋非常多,我這里只列出其中一部分,我們看到,我們可以訪(fǎng)問(wèn)files文件夾下的Music文件夾、Movies文件夾等等好幾種。
說(shuō)到這里,我想大家對內部存儲、外部存儲該有了一個(gè)清晰的認識了吧。我們在開(kāi)發(fā)中,不建議往內部存儲中寫(xiě)太多的數據,畢竟空間有限。外部存儲在使用的時(shí)候最好能夠將文件存放在私有目錄下,這樣有利于系統維護,也避免用戶(hù)的反感。
現在我們再來(lái)看看我們一開(kāi)始提出的問(wèn)題,當我們點(diǎn)擊清除數據的時(shí)候清除的是哪里的數據呢?毫無(wú)疑問(wèn),當然是內部存儲目錄中相應的files和cache文件夾中的文件和外部存儲中相應的files和cache文件夾中的文件,至于這些文件夾的路徑我想你應該已經(jīng)明白了。
好了,最后再送給大家一個(gè)文件操作工具類(lèi):
- public class SDCardHelper {
-
- // 判斷SD卡是否被掛載
- public static boolean isSDCardMounted() {
- // return Environment.getExternalStorageState().equals("mounted");
- return Environment.getExternalStorageState().equals(
- Environment.MEDIA_MOUNTED);
- }
-
- // 獲取SD卡的根目錄
- public static String getSDCardBaseDir() {
- if (isSDCardMounted()) {
- return Environment.getExternalStorageDirectory().getAbsolutePath();
- }
- return null;
- }
-
- // 獲取SD卡的完整空間大小,返回MB
- public static long getSDCardSize() {
- if (isSDCardMounted()) {
- StatFs fs = new StatFs(getSDCardBaseDir());
- long count = fs.getBlockCountLong();
- long size = fs.getBlockSizeLong();
- return count * size / 1024 / 1024;
- }
- return 0;
- }
-
- // 獲取SD卡的剩余空間大小
- public static long getSDCardFreeSize() {
- if (isSDCardMounted()) {
- StatFs fs = new StatFs(getSDCardBaseDir());
- long count = fs.getFreeBlocksLong();
- long size = fs.getBlockSizeLong();
- return count * size / 1024 / 1024;
- }
- return 0;
- }
-
- // 獲取SD卡的可用空間大小
- public static long getSDCardAvailableSize() {
- if (isSDCardMounted()) {
- StatFs fs = new StatFs(getSDCardBaseDir());
- long count = fs.getAvailableBlocksLong();
- long size = fs.getBlockSizeLong();
- return count * size / 1024 / 1024;
- }
- return 0;
- }
-
- // 往SD卡的公有目錄下保存文件
- public static boolean saveFileToSDCardPublicDir(byte[] data, String type,
- String fileName) {
- BufferedOutputStream bos = null;
- if (isSDCardMounted()) {
- File file = Environment.getExternalStoragePublicDirectory(type);
- try {
- bos = new BufferedOutputStream(new FileOutputStream(new File(
- file, fileName)));
- bos.write(data);
- bos.flush();
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- bos.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- return false;
- }
-
- // 往SD卡的自定義目錄下保存文件
- public static boolean saveFileToSDCardCustomDir(byte[] data, String dir,
- String fileName) {
- BufferedOutputStream bos = null;
- if (isSDCardMounted()) {
- File file = new File(getSDCardBaseDir() + File.separator + dir);
- if (!file.exists()) {
- file.mkdirs();// 遞歸創(chuàng )建自定義目錄
- }
- try {
- bos = new BufferedOutputStream(new FileOutputStream(new File(
- file, fileName)));
- bos.write(data);
- bos.flush();
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- bos.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- return false;
- }
-
- // 往SD卡的私有Files目錄下保存文件
- public static boolean saveFileToSDCardPrivateFilesDir(byte[] data,
- String type, String fileName, Context context) {
- BufferedOutputStream bos = null;
- if (isSDCardMounted()) {
- File file = context.getExternalFilesDir(type);
- try {
- bos = new BufferedOutputStream(new FileOutputStream(new File(
- file, fileName)));
- bos.write(data);
- bos.flush();
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- bos.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- return false;
- }
-
- // 往SD卡的私有Cache目錄下保存文件
- public static boolean saveFileToSDCardPrivateCacheDir(byte[] data,
- String fileName, Context context) {
- BufferedOutputStream bos = null;
- if (isSDCardMounted()) {
- File file = context.getExternalCacheDir();
- try {
- bos = new BufferedOutputStream(new FileOutputStream(new File(
- file, fileName)));
- bos.write(data);
- bos.flush();
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- bos.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- return false;
- }
-
- // 保存bitmap圖片到SDCard的私有Cache目錄
- public static boolean saveBitmapToSDCardPrivateCacheDir(Bitmap bitmap,
- String fileName, Context context) {
- if (isSDCardMounted()) {
- BufferedOutputStream bos = null;
- // 獲取私有的Cache緩存目錄
- File file = context.getExternalCacheDir();
-
- try {
- bos = new BufferedOutputStream(new FileOutputStream(new File(
- file, fileName)));
- if (fileName != null
- && (fileName.contains(".png") || fileName
- .contains(".PNG"))) {
- bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
- } else {
- bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
- }
- bos.flush();
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (bos != null) {
- try {
- bos.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- return true;
- } else {
- return false;
- }
- }
-
- // 從SD卡獲取文件
- public static byte[] loadFileFromSDCard(String fileDir) {
- BufferedInputStream bis = null;
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
- try {
- bis = new BufferedInputStream(
- new FileInputStream(new File(fileDir)));
- byte[] buffer = new byte[8 * 1024];
- int c = 0;
- while ((c = bis.read(buffer)) != -1) {
- baos.write(buffer, 0, c);
- baos.flush();
- }
- return baos.toByteArray();
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- baos.close();
- bis.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- return null;
- }
-
- // 從SDCard中尋找指定目錄下的文件,返回Bitmap
- public Bitmap loadBitmapFromSDCard(String filePath) {
- byte[] data = loadFileFromSDCard(filePath);
- if (data != null) {
- Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);
- if (bm != null) {
- return bm;
- }
- }
- return null;
- }
-
- // 獲取SD卡公有目錄的路徑
- public static String getSDCardPublicDir(String type) {
- return Environment.getExternalStoragePublicDirectory(type).toString();
- }
-
- // 獲取SD卡私有Cache目錄的路徑
- public static String getSDCardPrivateCacheDir(Context context) {
- return context.getExternalCacheDir().getAbsolutePath();
- }
-
- // 獲取SD卡私有Files目錄的路徑
- public static String getSDCardPrivateFilesDir(Context context, String type) {
- return context.getExternalFilesDir(type).getAbsolutePath();
- }
-
- public static boolean isFileExist(String filePath) {
- File file = new File(filePath);
- return file.isFile();
- }
-
- // 從sdcard中刪除文件
- public static boolean removeFileFromSDCard(String filePath) {
- File file = new File(filePath);
- if (file.exists()) {
- try {
- file.delete();
- return true;
- } catch (Exception e) {
- return false;
- }
- } else {
- return false;
- }
- }
- }
本文相關(guān)筆記和源碼下載http://download.csdn.net/detail/u012702547/9348985