Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android中的內部存儲與外部存儲

android中的內部存儲與外部存儲

編輯:關於Android編程

我們先來考慮這樣一個問題:

打開手機設置,選擇應用管理,選擇任意一個App,然後你會看到兩個按鈕,一個是清除緩存,另一個是清除數據,那麼當我們點擊清除緩存的時候清除的是哪裡的數據?當我們點擊清除數據的時候又是清除的哪裡的數據?讀完本文相信你會有答案。

在android開發中我們常常聽到這樣幾個概念,內存,內部存儲,外部存儲,很多人常常將這三個東西搞混,那麼我們今天就先來詳細說說這三個東西是怎麼回事?

內存,我們在英文中稱作memory,內部存儲,我們稱為InternalStorage,外部存儲我們稱為ExternalStorage,這在英文中本不會產生歧義,但是當我們翻譯為中文之後,前兩個都簡稱為內存,於是,混了。

那麼究竟什麼是內部存儲什麼是外部存儲呢?

首先我們打開DDMS,有一個File Explorer,如下:

 

這裡有三個文件夾需要我們重視,一個是data,一個是mnt,一個是storage,我們下面就詳細說說這三個文件夾。

1.內部存儲

data文件夾就是我們常說的內部存儲,當我們打開data文件夾之後(沒有root的手機不能打開該文件夾),裡邊有兩個文件夾值得我們關注,如下:

 

一個文件夾是app文件夾,還有一個文件夾就是data文件夾,app文件夾裡存放著我們所有安裝的app的apk文件,其實,當我們調試一個app的時候,可以看到控制台輸出的內容,有一項是uploading .....就是上傳我們的apk到這個文件夾,上傳成功之後才開始安裝。另一個重要的文件夾就是data文件夾了,這個文件夾裡邊都是一些包名,打開這些包名之後我們會看到這樣的一些文件:

1.data/data/包名/shared_prefs
2.data/data/包名/databases
3.data/data/包名/files

4.data/data/包名/cache

如果打開過data文件,應該都知道這些文件夾是干什麼用的,我們在使用sharedPreferenced的時候,將數據持久化存儲於本地,其實就是存在這個文件中的xml文件裡,我們App裡邊的數據庫文件就存儲於databases文件夾中,還有我們的普通數據存儲在files中,緩存文件存儲在cache文件夾中,存儲在這裡的文件我們都稱之為內部存儲。

2.外部存儲

外部存儲才是我們平時操作最多的,外部存儲一般就是我們上面看到的storage文件夾,當然也有可能是mnt文件夾,這個不同廠家有可能不一樣。

一般來說,在storage文件夾中有一個sdcard文件夾,這個文件夾中的文件又分為兩類,一類是公有目錄,還有一類是私有目錄,其中的公有目錄有九大類,比如DCIM、DOWNLOAD等這種系統為我們創建的文件夾,私有目錄就是Android這個文件夾,這個文件夾打開之後裡邊有一個data文件夾,打開這個data文件夾,裡邊有許多包名組成的文件夾。

說到這裡,我想大家應該已經可以分清楚什麼是內部存儲什麼是外部存儲了吧?好,分清楚之後我們就要看看怎麼來操作內部存儲和外部存儲了。

3.操作存儲空間

首先,經過上面的分析,大家已經明白了,什麼是內部存儲,什麼是外部存儲,以及這兩種存儲方式分別存儲在什麼位置,一般來說,我們不會自己去操作內部存儲空間,沒有root權限的話,我們也沒法操作內部存儲空間,事實上內部存儲主要是由系統來維護的。不過在代碼中我們是可以訪問到這個文件夾的。由於內部存儲空間有限,在開發中我們一般都是操作外部存儲空間,Google官方建議我們App的數據應該存儲在外部存儲的私有目錄中該App的包名下,這樣當用戶卸載掉App之後,相關的數據會一並刪除,如果你直接在/storage/sdcard目錄下創建了一個應用的文件夾,那麼當你刪除應用的時候,這個文件夾就不會被刪除。

經過以上的介紹,我們可以總結出下面一個表格:

 

一目了然,什麼是內部存儲,什麼是外部存儲。

如果按照路徑的特征,我們又可以將文件存儲的路徑分為兩大類,一類是路徑中含有包名的,一類是路徑中不含有包名的,含有包名的路徑,因為和某個App有關,所以對這些文件夾的訪問都是調用Context裡邊的方法,而不含有包名的路徑,和某一個App無關,我們可以通過Environment中的方法來訪問。如下圖:

 

大家看到,有包名的路徑我們都是調用Context中的方法來獲得,沒有包名的路徑,我們直接調用Environment中的方法獲得,那麼其中有兩個方法需要傳入一個String類型的參數,這個參數我們使用了Environment中的常量,參數的意思是我們要訪問這個路徑下的哪個文件夾,比如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);

它的注釋非常多,我這裡只列出其中一部分,我們看到,我們可以訪問files文件夾下的Music文件夾、Movies文件夾等等好幾種。

 

說到這裡,我想大家對內部存儲、外部存儲該有了一個清晰的認識了吧。我們在開發中,不建議往內部存儲中寫太多的數據,畢竟空間有限。外部存儲在使用的時候最好能夠將文件存放在私有目錄下,這樣有利於系統維護,也避免用戶的反感。

現在我們再來看看我們一開始提出的問題,當我們點擊清除數據的時候清除的是哪裡的數據呢?毫無疑問,當然是內部存儲目錄中相應的files和cache文件夾中的文件和外部存儲中相應的files和cache文件夾中的文件,至於這些文件夾的路徑我想你應該已經明白了。

好了,最後再送給大家一個文件操作工具類:

 

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();// 遞歸創建自定義目錄
			}
			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;
		}
	}
}

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved