關於Android的File存儲,這里先說下Java中的File類,根據面向對象的思想,Java中對文件的操作也進行了對象的封裝,這個操作文件的類就是File類,File提供了豐富的api來進行文件的操作,比如常見的createNewFile(),mkdir(),mkdirs(),exists(),isFile(),isDictory(),renameto(),delete(),getName(),getPath()....方法比較多,讀者可以自行通過api文檔查看,同樣這一套的文件操作在Android中也適用。
下面對幾個常用的api進行說明舉例。
File構造函數
/** *這里通過將給定路徑名字符串轉換為抽象路徑名來創建一個新File實例。 *然后執行file.createNewFile();如果該文件存在,則創建失敗,不存在則創建,返回一個boolean值 */ File file=new File(String pathname);
/** *這里根據parent抽象路徑名和child路徑名字符串創建一個新File實例。 *執行file.createNewFile();如果parent抽象路徑名不存在,或者文件已經創建過,依然不能創建成功。 */ File file=new File(File parent,String child);
/** *根據 parent 路徑名字符串和 child 路徑名字符串創建一個新 File 實例。 *執行file.createNewFile();如果parent抽象路徑名不存在,或者文件已經創建過,依然不能創建成功。 */ File file=new File(String parentpath,String child);
File常用方法
- createNewFile();如果文件已經存在,則創建失敗,否則成功創建,還有其他可能
- mkdir();創建文件夾,注意:如果創建目標文件夾的父級目錄不存在,就會創建失敗
- mkdirs();創建多級目錄,父級文件目錄不存在的話,會自動創建父級目錄。
- isFile();判斷是否是一個文件
- isDictory();判斷是否是一個文件夾
- delete();刪除文件或者文件夾,注意要是刪除文件夾的時候,文件夾里還有文件或者文件夾,則不能刪除,意思是只能刪除一個空文件夾。
- exists();判斷文件或者文件夾是否存在
- getName();獲取文件或者文件夾的名稱
- getPath();獲取相對路徑
- getAbsolutePath();獲取絕對路徑
- length();獲取文件或者文件夾的長度
Android中的File存儲
- 在介紹如何在Android平台下進行文件的讀取之前,有必要了解Android平台下的數據存儲規則。在其他的操作系統如Windows 平台下,應用程序可以自由地或者在特定的訪問權限基礎上訪問或修改其他應用程序名下的文件等資源,而在Android平台下,一個應用程序中所有的數據都是私有的。
- 當應用程序被安裝到系統中后,其所在的包會有一個文件夾用於存放自己的數據,只有這個應用程序才有對這個文件夾的寫入權限,這個私有的文件夾位於Android系統的/data/data/<應用程序包名>目錄下,其他的應用程序都無法再這個文件夾中寫入數據。除了存放私有的數據文件夾外,應用程序也具有SD卡的寫入權限。
- 使用文件I/O 方法可以直接往手機中存儲數據,默認情況下這些文件不可以被其他的應用程序訪問。Android平台支持 java平台下的 文件I/O操作, 主要使用FileInputStream 和 FileOutputStream 這兩個類來實現文件的存儲與讀取。獲取這兩個類對象的方式有兩種。
- 第一種方式就是像Java平台下的實現方式一樣通過構造器直接創建,如果需要向打開的文件末尾寫入數據,可以通過使用構造器FileOutputStream(File file, boolean append)將 append設置為true來實現。不過需要注意的是采用這種方式獲得FileOutputStream 對象時如果文件不存在或不可寫入時,會拋出 FileNotFoundException 異常。
- 第二種獲取 FileInputStream 和 FileOutputStream 對象的方式是調用 Context.openFileInput 和 Context.openFileOutput兩個方法來創建。
方法說明
-
- openFileInput(String filename) 打開應用程序私有目錄下的的指定私有文件以讀入數據,返回一個FileInputStream 對象,如果該文件不存在,依然會發生異常,FileNotFoundException
- openFileOutput(String fileName,int mode) 打開應用程序私有目錄下的的指定私有文件以寫入數據,返回一個FileOutputStream 對象,如果文件不存在就創建這個文件。
除了這兩個方法外,Context對象還提供了其他幾個用於對文件操作的方法,如下所示
- fileList() 搜索應用程序私有文件夾下的私有文件,返回所有文件名的String數組
- deleteFile(String fileName) 刪除指定文件名的文件,成功返回true,失敗返回false
在使用openFileOutput方法打開文件以寫入數據時,需要指定打開模式。默認為零,即MODE_PRIVATE。不同的模式對應的的含義如下:
常量 含義
MODE_PRIVATE
默認模式,文件只可以被調用該方法的應用程序訪問
MODE_APPEND
如果文件已存在就向該文件的末尾繼續寫入數據,而不是覆蓋原來的數據。
MODE_WORLD_READABLE
賦予所有的應用程序對該文件讀的權限。
MODE_WORLD_WRITEABLE
賦予所有的應用程序對該文件寫的權限。
但是Android 4.2開始,Android不推薦使用,MODE_WORLD_READABLE ,MODE_WORLD_WRITEABLE 這兩種模式。
App在手機上保存文件或者緩存數據時,應該遵守以下幾點:
- 不要隨意占用用戶的內置存儲。
- 不要隨意在SD卡上新建目錄,應該放置自己應用包名對應的擴展存儲目錄下,卸載App時可以被自動清除。
- 對占用的磁盤空間有上限,並按照一定的策略進行清除。
Android下有哪些文件目錄
應用私有存儲(內置存儲)
獲取方式:
Context.getFileDir():獲取內置存儲下的文件目錄,可以用來保存不能公開給其他應用的一些敏感數據如用戶個人信息
Context.getCacheDir():獲取內置存儲下的緩存目錄,可以用來保存一些緩存文件如圖片,當內置存儲的空間不足時將系統自動被清除
絕對路徑:
Context.getFileDir():/data/data/應用包名/files/
Context.getCacheDir():/data/data/應用包名/cache/
寫權限:不需要申請
這是手機的內置存儲,沒有root的過的手機是無法用文件管理器之類的工具查看的。而且這些數據也會隨着用戶卸載App而被一起刪除。這兩個目錄其實就對應着設置->應用->你的App->存儲空間下面的清除數據和清楚如下圖所示
應用擴展存儲(SD卡)
獲取方式:
Context.getExternalFilesDir():獲取SD卡上的文件目錄
Context.getExternalCacheDir():獲取SD卡上的緩存目錄
絕對路徑:
Context.getExternalFilesDir():SDCard/Android/data/應用包名/files/
Context.getExternalCacheDir():SDCard/Android/data/應用包名/cache/
寫權限:
API < 19:需要申請
API >= 19:不需要申請
既然是SD卡上的目錄,那么是可以被其他的應用讀取到的,所以這個目錄下,不應該存放用戶的敏感信息。同上面一樣的,這里的文件會隨着App卸載而被刪除,也可以由用戶手動在設置界面里面清除。
公共存儲(SD卡)
獲取方式:Environment.getExternalStorageDirectory()
絕對路徑:SDCard/你設置的文件夾名字/
寫權限:需要申請
如果我們的App需要存儲一些公共的文件,甚至希望下載下來的文件即使在我們的App被刪除之后,還可以被其他App使用,那么就可以使用這個目錄。這個目錄是始終需要申請SD寫入權限的。
Android6.0下應該把文件放到哪里?
根據最開始提到的規則,其實如果僅僅是做了簡單的圖片緩存工作,那么我們應該把圖片緩存放到/data/data/應用包名/cache/或者SDCard/Android/data/應用包名/cache/,因為在6.0系統(API23)時,不需要申請權限就可以向這兩個目錄寫入文件。而且/data/data/應用包名/cache/目錄,是內置存儲的應用私有緩存目錄,在系統空間不夠時還會被自動清除,對於圖片緩存來講也是一個不錯的管理策略,不過谷歌建議我們最好還是自己實現緩存清除管理,例如用DiskLruCache。