徹底了解android中的內部存儲與外部存儲


徹底了解android中的內部存儲與外部存儲

 

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

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

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

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

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

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

徹底理解android中的內部存儲與外部存儲0

這里有三個文件夾需要我們重視,一個是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方法,我們看看它的源碼:

 

  1   /**
  2      *
  3      * @param type The type of files directory to return.  May be null for
  4      * the root of the files directory or one of
  5      * the following Environment constants for a subdirectory:
  6      * {@link android.os.Environment#DIRECTORY_MUSIC},
  7      * {@link android.os.Environment#DIRECTORY_PODCASTS},
  8      * {@link android.os.Environment#DIRECTORY_RINGTONES},
  9      * {@link android.os.Environment#DIRECTORY_ALARMS},
 10      * {@link android.os.Environment#DIRECTORY_NOTIFICATIONS},
 11      * {@link android.os.Environment#DIRECTORY_PICTURES}, or
 12      * {@link android.os.Environment#DIRECTORY_MOVIES}.
 13      *
 14      * @return The path of the directory holding application files
 15      * on external storage.  Returns null if external storage is not currently
 16      * mounted so it could not ensure the path exists; you will need to call
 17      * this method again when it is available.
 18      *
 19      * @see #getFilesDir
 20      * @see android.os.Environment#getExternalStoragePublicDirectory
 21      */
 22     @Nullable
 23     public abstract File getExternalFilesDir(@Nullable String type);
 24 它的注釋非常多,我這里只列出其中一部分,我們看到,我們可以訪問files文件夾下的Music文件夾、Movies文件夾等等好幾種。
 25 
 26  
 27 
 28 說到這里,我想大家對內部存儲、外部存儲該有了一個清晰的認識了吧。我們在開發中,不建議往內部存儲中寫太多的數據,畢竟空間有限。外部存儲在使用的時候最好能夠將文件存放在私有目錄下,這樣有利於系統維護,也避免用戶的反感。
 29 
 30 現在我們再來看看我們一開始提出的問題,當我們點擊清除數據的時候清除的是哪里的數據呢?毫無疑問,當然是內部存儲目錄中相應的files和cache文件夾中的文件和外部存儲中相應的files和cache文件夾中的文件,至於這些文件夾的路徑我想你應該已經明白了。
 31 
 32 好了,最后再送給大家一個文件操作工具類:
 33 
 34  
 35 
 36 public class SDCardHelper {
 37 
 38     // 判斷SD卡是否被掛載
 39     public static boolean isSDCardMounted() {
 40         // return Environment.getExternalStorageState().equals("mounted");
 41         return Environment.getExternalStorageState().equals(
 42                 Environment.MEDIA_MOUNTED);
 43     }
 44 
 45     // 獲取SD卡的根目錄
 46     public static String getSDCardBaseDir() {
 47         if (isSDCardMounted()) {
 48             return Environment.getExternalStorageDirectory().getAbsolutePath();
 49         }
 50         return null;
 51     }
 52 
 53     // 獲取SD卡的完整空間大小,返回MB
 54     public static long getSDCardSize() {
 55         if (isSDCardMounted()) {
 56             StatFs fs = new StatFs(getSDCardBaseDir());
 57             long count = fs.getBlockCountLong();
 58             long size = fs.getBlockSizeLong();
 59             return count * size / 1024 / 1024;
 60         }
 61         return 0;
 62     }
 63 
 64     // 獲取SD卡的剩余空間大小
 65     public static long getSDCardFreeSize() {
 66         if (isSDCardMounted()) {
 67             StatFs fs = new StatFs(getSDCardBaseDir());
 68             long count = fs.getFreeBlocksLong();
 69             long size = fs.getBlockSizeLong();
 70             return count * size / 1024 / 1024;
 71         }
 72         return 0;
 73     }
 74 
 75     // 獲取SD卡的可用空間大小
 76     public static long getSDCardAvailableSize() {
 77         if (isSDCardMounted()) {
 78             StatFs fs = new StatFs(getSDCardBaseDir());
 79             long count = fs.getAvailableBlocksLong();
 80             long size = fs.getBlockSizeLong();
 81             return count * size / 1024 / 1024;
 82         }
 83         return 0;
 84     }
 85 
 86     // 往SD卡的公有目錄下保存文件
 87     public static boolean saveFileToSDCardPublicDir(byte[] data, String type,
 88             String fileName) {
 89         BufferedOutputStream bos = null;
 90         if (isSDCardMounted()) {
 91             File file = Environment.getExternalStoragePublicDirectory(type);
 92             try {
 93                 bos = new BufferedOutputStream(new FileOutputStream(new File(
 94                         file, fileName)));
 95                 bos.write(data);
 96                 bos.flush();
 97                 return true;
 98             } catch (Exception e) {
 99                 e.printStackTrace();
100             } finally {
101                 try {
102                     bos.close();
103                 } catch (IOException e) {
104                     // TODO Auto-generated catch block
105                     e.printStackTrace();
106                 }
107             }
108         }
109         return false;
110     }
111 
112     // 往SD卡的自定義目錄下保存文件
113     public static boolean saveFileToSDCardCustomDir(byte[] data, String dir,
114             String fileName) {
115         BufferedOutputStream bos = null;
116         if (isSDCardMounted()) {
117             File file = new File(getSDCardBaseDir() + File.separator + dir);
118             if (!file.exists()) {
119                 file.mkdirs();// 遞歸創建自定義目錄
120             }
121             try {
122                 bos = new BufferedOutputStream(new FileOutputStream(new File(
123                         file, fileName)));
124                 bos.write(data);
125                 bos.flush();
126                 return true;
127             } catch (Exception e) {
128                 e.printStackTrace();
129             } finally {
130                 try {
131                     bos.close();
132                 } catch (IOException e) {
133                     // TODO Auto-generated catch block
134                     e.printStackTrace();
135                 }
136             }
137         }
138         return false;
139     }
140 
141     // 往SD卡的私有Files目錄下保存文件
142     public static boolean saveFileToSDCardPrivateFilesDir(byte[] data,
143             String type, String fileName, Context context) {
144         BufferedOutputStream bos = null;
145         if (isSDCardMounted()) {
146             File file = context.getExternalFilesDir(type);
147             try {
148                 bos = new BufferedOutputStream(new FileOutputStream(new File(
149                         file, fileName)));
150                 bos.write(data);
151                 bos.flush();
152                 return true;
153             } catch (Exception e) {
154                 e.printStackTrace();
155             } finally {
156                 try {
157                     bos.close();
158                 } catch (IOException e) {
159                     // TODO Auto-generated catch block
160                     e.printStackTrace();
161                 }
162             }
163         }
164         return false;
165     }
166 
167     // 往SD卡的私有Cache目錄下保存文件
168     public static boolean saveFileToSDCardPrivateCacheDir(byte[] data,
169             String fileName, Context context) {
170         BufferedOutputStream bos = null;
171         if (isSDCardMounted()) {
172             File file = context.getExternalCacheDir();
173             try {
174                 bos = new BufferedOutputStream(new FileOutputStream(new File(
175                         file, fileName)));
176                 bos.write(data);
177                 bos.flush();
178                 return true;
179             } catch (Exception e) {
180                 e.printStackTrace();
181             } finally {
182                 try {
183                     bos.close();
184                 } catch (IOException e) {
185                     // TODO Auto-generated catch block
186                     e.printStackTrace();
187                 }
188             }
189         }
190         return false;
191     }
192 
193     // 保存bitmap圖片到SDCard的私有Cache目錄
194     public static boolean saveBitmapToSDCardPrivateCacheDir(Bitmap bitmap,
195             String fileName, Context context) {
196         if (isSDCardMounted()) {
197             BufferedOutputStream bos = null;
198             // 獲取私有的Cache緩存目錄
199             File file = context.getExternalCacheDir();
200 
201             try {
202                 bos = new BufferedOutputStream(new FileOutputStream(new File(
203                         file, fileName)));
204                 if (fileName != null
205                         && (fileName.contains(".png") || fileName
206                                 .contains(".PNG"))) {
207                     bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
208                 } else {
209                     bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
210                 }
211                 bos.flush();
212             } catch (Exception e) {
213                 e.printStackTrace();
214             } finally {
215                 if (bos != null) {
216                     try {
217                         bos.close();
218                     } catch (IOException e) {
219                         e.printStackTrace();
220                     }
221                 }
222             }
223             return true;
224         } else {
225             return false;
226         }
227     }
228 
229     // 從SD卡獲取文件
230     public static byte[] loadFileFromSDCard(String fileDir) {
231         BufferedInputStream bis = null;
232         ByteArrayOutputStream baos = new ByteArrayOutputStream();
233 
234         try {
235             bis = new BufferedInputStream(
236                     new FileInputStream(new File(fileDir)));
237             byte[] buffer = new byte[8 * 1024];
238             int c = 0;
239             while ((c = bis.read(buffer)) != -1) {
240                 baos.write(buffer, 0, c);
241                 baos.flush();
242             }
243             return baos.toByteArray();
244         } catch (Exception e) {
245             e.printStackTrace();
246         } finally {
247             try {
248                 baos.close();
249                 bis.close();
250             } catch (IOException e) {
251                 e.printStackTrace();
252             }
253         }
254         return null;
255     }
256 
257     // 從SDCard中尋找指定目錄下的文件,返回Bitmap
258     public Bitmap loadBitmapFromSDCard(String filePath) {
259         byte[] data = loadFileFromSDCard(filePath);
260         if (data != null) {
261             Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);
262             if (bm != null) {
263                 return bm;
264             }
265         }
266         return null;
267     }
268 
269     // 獲取SD卡公有目錄的路徑
270     public static String getSDCardPublicDir(String type) {
271         return Environment.getExternalStoragePublicDirectory(type).toString();
272     }
273 
274     // 獲取SD卡私有Cache目錄的路徑
275     public static String getSDCardPrivateCacheDir(Context context) {
276         return context.getExternalCacheDir().getAbsolutePath();
277     }
278 
279     // 獲取SD卡私有Files目錄的路徑
280     public static String getSDCardPrivateFilesDir(Context context, String type) {
281         return context.getExternalFilesDir(type).getAbsolutePath();
282     }
283 
284     public static boolean isFileExist(String filePath) {
285         File file = new File(filePath);
286         return file.isFile();
287     }
288 
289     // 從sdcard中刪除文件
290     public static boolean removeFileFromSDCard(String filePath) {
291         File file = new File(filePath);
292         if (file.exists()) {
293             try {
294                 file.delete();
295                 return true;
296             } catch (Exception e) {
297                 return false;
298             }
299         } else {
300             return false;
301         }
302     }
303 }

 

 本文相關筆記和源碼下載http://download.csdn.net/detail/u012702547/9348985


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM