一晨另、Android緩存機制
Android緩存分為內(nèi)存緩存和文件緩存(磁盤緩存)鹃栽。在早期档玻,各大圖片緩存框架流行之前怀泊,常用的內(nèi)存緩存方式是軟引用(SoftReference)和弱引用(WeakReference),如大部分的使用方式:HashMap<String url, SoftReference<Drawable>> imageCache;這種形式误趴。從Android 2.3(Level 9)開始霹琼,垃圾回收器更傾向于回收SoftReference或WeakReference對象,這使得SoftReference和WeakReference變得不是那么實用有效凉当。同時枣申,到了Android 3.0(Level 11)之后,圖片數(shù)據(jù)Bitmap被放置到了內(nèi)存的堆區(qū)域看杭,而堆區(qū)域的內(nèi)存是由GC管理的忠藤,開發(fā)者也就不需要進行圖片資源的釋放工作,但這也使得圖片數(shù)據(jù)的釋放無法預知楼雹,增加了造成OOM的可能模孩。因此尖阔,在Android3.1以后,Android推出了LruCache這個內(nèi)存緩存類榨咐,LruCache中的對象是強引用的介却。
二、二級緩存工作機制
所謂二級緩存實際上并不復雜块茁,當Android端需要獲得數(shù)據(jù)時比如獲取網(wǎng)絡中的圖片齿坷,我們首先從內(nèi)存中查找(按鍵查找),內(nèi)存中沒有的再從磁盤文件或sqlite中去查找龟劲,若磁盤中也沒有才通過網(wǎng)絡獲任赶摹;當獲得來自網(wǎng)絡的數(shù)據(jù)昌跌,就以key-value對的方式先緩存到內(nèi)存(一級緩存)仰禀,同時緩存到文件或sqlite中(二級緩存)。注意:內(nèi)存緩存會造成堆內(nèi)存泄露蚕愤,所有一級緩存通常要嚴格控制緩存的大小答恶,一般控制在系統(tǒng)內(nèi)存的1/4。
三萍诱、離線緩存
離線緩存就是在網(wǎng)絡暢通的情況下將從服務器收到的數(shù)據(jù)保存到本地悬嗓,當網(wǎng)絡斷開之后直接讀取本地文件中的數(shù)據(jù)。本質(zhì)就是要控制好文件的存儲裕坊、讀取包竹。
我們的應用程序一般會產(chǎn)生以下幾種類型的數(shù)據(jù):
file-普通的文件存儲
database-數(shù)據(jù)庫文件(.db文件)
sharedPreference-配置數(shù)據(jù)(.xml文件)
cache-圖片緩存文件
應用內(nèi)數(shù)據(jù)的所有路徑:
/data/data/com.xxx.xxx/cache - 應用內(nèi)緩存(注:對應方法getCacheDir())
/data/data/com.xxx.xxx/databases - 應用內(nèi)數(shù)據(jù)庫
/data/data/com.xxx.xxx/shared_prefs - 應用內(nèi)配置文件
/data/data/com.xxx.xxx/files - 應用內(nèi)文件(注:對應方法getFilesDir())
SD卡的文件(開發(fā)者自定義的)
不管是內(nèi)置還是外置SD卡,獲取路徑的方法是一樣:
獲取SD卡根目錄:Environment.getExternalStorageDirectory().getAbsolutePath();
外部Cache路徑:/mnt/sdcard/android/data/com.xxx.xxx/cache 一般存儲緩存數(shù)據(jù)(注:通過getExternalCacheDir()獲燃)
外部File路徑:/mnt/sdcard/android/data/com.xxx.xxx/files 存儲長時間存在的數(shù)據(jù) (注:通過getExternalFilesDir(String type)獲取周瞎, type為特定類型,可以是以下任何一種
Environment.DIRECTORY_MUSIC, Environment.DIRECTORY_PODCASTS, Environment.DIRECTORY_RINGTONES, Environment.DIRECTORY_ALARMS, Environment.DIRECTORY_NOTIFICATIONS, Environment.DIRECTORY_PICTURES, or Environment.DIRECTORY_MOVIES. )
四饵蒂、Android常用存儲:
Android平臺進行數(shù)據(jù)存儲的五大方式,分別如下:
1 使用SharedPreferences存儲數(shù)據(jù)
2 文件存儲數(shù)據(jù)
3 SQLite數(shù)據(jù)庫存儲數(shù)據(jù)
4 使用ContentProvider存儲數(shù)據(jù)
5 網(wǎng)絡存儲數(shù)據(jù)
以下介紹了前兩種的使用声诸,數(shù)據(jù)庫可以使用庫比較方便,如:greenDao; 其他不過多介紹退盯。主要針對緩存做介紹彼乌。
(一)、SharedPreferences詳解
使用 SharedPreferences 保存key-value對的步驟一般是這樣:
使用Activity類的getSharedPreferences方法獲取到 SharedPreferences 對象渊迁,指定文件名和訪問權限
獲得SharedPreferences.Editor對象慰照,并使用該對象的 putXxx方法保存key-value對。
通過SharedPreferences.Editor的commit方法保存(提交)key-value對琉朽。
(1)獲取SharedPreferences的兩種方式:
1 調(diào)用Context對象的getSharedPreferences()方法
2 調(diào)用Activity對象的getPreferences()方法
(2)兩種方式的區(qū)別:
調(diào)用Context對象的getSharedPreferences()方法獲得的SharedPreferences對象可以被同一應用程序下的其他組件共享.
調(diào)用Activity對象的getPreferences()方法獲得的SharedPreferences對象只能在該Activity中使用.
(3)SharedPreferences的四種操作模式:
Context.MODE_PRIVATE
Context.MODE_APPEND
Context.MODE_WORLD_READABLE
Context.MODE_WORLD_WRITEABLE
Context.MODE_PRIVATE:為默認操作模式,代表該文件是私有數(shù)據(jù),只能被應用本身訪問,在該模式下,寫入的內(nèi)容會覆蓋原文件的內(nèi)容
Context.MODE_APPEND:模式會檢查文件是否存在,存在就往文件追加內(nèi)容,否則就創(chuàng)建新文件.
Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用來控制其他應用是否有權限讀寫該文件.
MODE_WORLD_READABLE:表示當前文件可以被其他應用讀取.
MODE_WORLD_WRITEABLE:表示當前文件可以被其他應用寫入.
(4)將數(shù)據(jù)保存至SharedPreferences:
SharedPreferences sp = getSharedPreferences("sp_demo", Context.MODE_PRIVATE);
sp.edit().putString("name", "小張").putInt("age", 11).commit();
或者下面的寫法也可以
SharedPreferences preferences=getSharedPreferences("user",Context.MODE_PRIVATE);
Editor editor=preferences.edit();
String name="xixi";
String age="22";
editor.putString("name", name);
editor.putString("age", age);
editor.commit();
(5)從SharedPreferences獲取數(shù)據(jù):
SharedPreferences preferences=getSharedPreferences("user", Context.MODE_PRIVATE);
String name=preferences.getString("name", "defaultname");
String age=preferences.getString("age", "0");
(二)毒租、文件存儲(File)詳解
文件存儲是 Android 中最基本的一種數(shù)據(jù)存儲方式,它不對存儲的內(nèi)容進行任何的格式化處理漓骚,所有數(shù)據(jù)都是原封不動的保存到文件當中的蝌衔。它比較適合用于存儲一些簡單的文本數(shù)據(jù)或二進制數(shù)據(jù)。如果你想使用文件存儲方式來保存一些較為復雜的文本數(shù)據(jù)蝌蹂,就需要定義一套自己的格式規(guī)范噩斟,方便于之后將文件重新解析出來。
(1)Context 提供的文件存儲方法(openFileOutput孤个、openFileInput)
- Context 類中提供了一個openFileOutput()方法剃允,可以用于將數(shù)據(jù)存儲到指定的文件中。
- 這個方法接收兩個參數(shù)齐鲤,第一個參數(shù)是文件創(chuàng)建時使用的名稱斥废,注意這里指定的文件名不可以包含路徑,因為所有文件都是默認儲存到 /data/data/<包名>/files/ 目錄下的给郊。
- 第二個參數(shù)是文件的操作模式牡肉,主要有兩種模式可選,MODE_PRIVATE(覆蓋原文) 和 MODE_APPEND(追加內(nèi)容) 淆九。
- openFileOutput() 方法返回的是一個 FileOutputStream 對象统锤,得到這個對象之后就可以使用 Java 流的方式將數(shù)據(jù)寫入到文件中了。
(I)將一段文本內(nèi)容保存到文件中:
public void save() {
String data = "hello to save";
FileOutputStream out = null;
BufferedWriter writer = null;
try {
//設置文件名稱炭庙,以及存儲方式
out = openFileOutput("data", Context.MODE_PRIVATE);
//創(chuàng)建一個OutputStreamWriter對象饲窿,傳入BufferedWriter的構造器中
writer = new BufferedWriter(new OutputStreamWriter(out));
//向文件中寫入數(shù)據(jù)
writer.write(data);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意:文件默認會存儲到/data/data/package/files中;
類似于將數(shù)據(jù)存儲到文件中苛茂,Context 類中還提供了一個 openFileInput()方法姿骏,用于從文件中讀取數(shù)據(jù)结借。
openFileInput() 方法只接收一個參數(shù),即要讀取的文件名鸦泳,然后系統(tǒng)會自動到 /data/data/<包名>/files/ 目錄下去加載這個文件,并返回一個 FileInputStream 對象迹卢。
(II)展示如何從文件中讀取文本數(shù)據(jù):
public String load() {
FileInputStream in = null;
BufferedReader reader = null;
StringBuilder content = new StringBuilder();
try {
//設置將要打開的存儲文件名稱
in = openFileInput("data");
//FileInputStream -> InputStreamReader ->BufferedReader
reader = new BufferedReader(new InputStreamReader(in));
String line = new String();
//讀取每一行數(shù)據(jù)辽故,并追加到StringBuilder對象中,直到結束
while ((line = reader.readLine()) != null) {
content.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return content.toString();
}
(III)四種文件保存的模式腐碱。
Context.MODE_PRIVATE 為默認操作模式誊垢,代表該文件是私有數(shù)據(jù),只能被應用本身訪問症见,在該模式下寫入的內(nèi)容會覆蓋原文件的內(nèi)容喂走。
Context.MODE_APPEND 檢查文件是否存在,存在就往文件追加內(nèi)容谋作,否則就創(chuàng)建新文件芋肠。
MODE_WORLD_READABLE 表示當前文件可以被其他應用讀取。
MODE_WORLD_WRITEABLE 表示當前文件可以被其他應用寫入遵蚜。
(2)內(nèi)部存儲:一般IO流操作File
注意內(nèi)部存儲不是內(nèi)存帖池。內(nèi)部存儲位于系統(tǒng)中很特殊的一個位置奈惑,如果你想將文件存儲于內(nèi)部存儲中,那么文件默認只能被你的應用訪問到睡汹,且一個應用所創(chuàng)建的所有文件都在和應用包名相同的目錄下肴甸。也就是說應用創(chuàng)建于內(nèi)部存儲的文件,與這個應用是關聯(lián)起來的囚巴。當一個應用卸載之后原在,內(nèi)部存儲中的這些文件也被刪除。從技術上來講如果你在創(chuàng)建內(nèi)部存儲文件的時候?qū)⑽募傩栽O置成可讀彤叉,其他app能夠訪問自己應用的數(shù)據(jù)庶柿,前提是他知道你這個應用的包名,如果一個文件的屬性是私有(private)秽浇,那么即使知道包名其他應用也無法訪問浮庐。 內(nèi)部存儲空間十分有限,因而顯得可貴兼呵,另外兔辅,它也是系統(tǒng)本身和系統(tǒng)應用程序主要的數(shù)據(jù)存儲所在地,一旦內(nèi)部存儲空間耗盡击喂,手機也就無法使用了维苔。所以對于內(nèi)部存儲空間,我們要盡量避免使用懂昂。Shared Preferences和SQLite數(shù)據(jù)庫都是存儲在內(nèi)部存儲空間上的介时。內(nèi)部存儲一般用Context來獲取和操作。
getFilesDir()獲取你app的內(nèi)部存儲空間凌彬,相當于你的應用在內(nèi)部存儲上的根目錄沸柔。
應用安裝后都會在Android 根目錄生成 /data/data/packagename,當前應用讀取不需要讀寫權限
注意:
有些開發(fā)者可能看到過應用的根目錄為 /data/user/0/packagename 的情況铲敛,這里解釋一下褐澎,Android 4.2 版本添加了同一設備可以登錄不同用戶的功能(由于專利原因僅限于平板電腦,手機不支持此功能)伐蒋,所以為了區(qū)分不同用戶在同一應用中的設置和存儲的數(shù)據(jù)工三,添加了該系列的路徑,該路徑指向 /data/data/packagename
- getFileDir() 方法得到的是該目錄下 files 文件夾的 File 對象
- getChacheDir() 方法得到的是該目錄下 cache 文件夾的 File 對象
- 直接調(diào)用ContextWrapper的 openFileOutput(String name,int mode) 也會在該目錄下 files 文件夾下創(chuàng)建相應的文件先鱼,并且是私密的俭正。可以修改為其他應用可訪問的焙畔,通過 openFileOutput 方法的 mode 參數(shù)來完成
注意:
該目錄只有 root 權限下可以查看掸读,會隨著應用卸載刪除
應用程序詳情中清除數(shù)據(jù)會將 packagename 下所有數(shù)據(jù)以及內(nèi)置存儲、外置 SD 卡存儲空間中 /Android/data/packagename 的整個目錄刪除刪除
應用程序詳情中清除緩存會將 packagename/cache 目錄下所有數(shù)據(jù)以及內(nèi)置存儲、外置 SD 卡存儲空間中 /Android/data/packagename/cache 的整個目錄刪除
如果是要創(chuàng)建一個文件儿惫,如下
File file = newFile(context.getFilesDir(), filename);`
安卓還為我們提供了一個簡便方法 openFileOutput()`來讀寫應用在內(nèi)部存儲空間上的文件澡罚,下面是一個向文件中寫入文本的例子:(參考以上)
String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;
try{
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(string.getBytes());
outputStream.close();
} catch(Exception e) {
e.printStackTrace();
}
內(nèi)部存儲的其他一些操作:
A.列出所有的已創(chuàng)建的文件,這個可能不容易想到,Context
居然有這樣的方法肾请。
String[] files = Context.fileList();
for(String file : files) {
Log.e(TAG, "file is "+ file);
}
B.刪除文件始苇,能創(chuàng)建就要能夠刪除,當然也會提供了刪除文件的接口筐喳,它也非常簡單,只需要提供文件名
if(Context.deleteFile(filename)) {
Log.e(TAG, "delete file "+ filename + " sucessfully“);
} else {
Log.e(TAG, "failed to deletefile " + filename);
}
C.創(chuàng)建一個目錄函喉,需要傳入目錄名稱避归,它返回 一個文件對象用到操作路徑
File workDir = Context.getDir(dirName, Context.MODE_PRIVATE);
Log.e(TAG, "workdir "+ workDir.getAbsolutePath();
總結一下文件相關操作,可以得出以下三個特點:
- 文件操作只需要向函數(shù)提供文件名管呵,所以程序自己只需要維護文件名即可梳毙;
- 不用自己去創(chuàng)建文件對象和輸入、輸出流捐下,提供文件名就可以返回File對象或輸入輸出流
- 對于路徑操作返回的都是文件對象账锹。
(3)外部存儲:IO(讀寫sdcard上的文件)
手機自帶 ROM 的存儲路徑
1、getExternalCacheDir() 方法坷襟,獲取內(nèi)置存儲卡中 /Android/data/packagename/cache 目錄的路徑奸柬,4.4及之后讀寫不需要權限,會隨著應用卸載刪除
2婴程、getExternalFilesDir() 方法廓奕,獲取內(nèi)置存儲卡中 /Android/data/packagename/files 目錄的路徑,4.4之后讀寫不需要權限档叔,會隨著應用卸載刪除桌粉,該方法參數(shù)為 "null" 時不指定子文件夾,指定時創(chuàng)建子文件夾保存文件衙四。創(chuàng)建的文件其他應用只要有讀寫權限也可以讀取铃肯,如果要私密的就使用內(nèi)部存儲。
3传蹈、Environment.getExternalStorageDirectory() 方法得到的是內(nèi)置存儲目錄的根路徑目錄,讀寫需要權限押逼,不會隨著應用卸載刪除
4、Environment.getExternalStoragePublicDirectory() 方法得到的是內(nèi)置存儲目錄根路徑下的特定類型文件的公共目錄卡睦,讀寫需要權限,不會隨著應用卸載刪除
5宴胧、注意,內(nèi)置存儲中 /Android/data/packagenaem/ 路徑的讀寫 Android 版本不同表锻,需要權限不同恕齐,所以開發(fā)時應始終聲明讀寫權限
其中讀寫步驟按如下進行:
1、調(diào)用Environment的getExternalStorageState()方法判斷手機上是否插了sd卡,且應用程序具有讀寫SD卡的權限,如下代碼將返回true
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
2显歧、調(diào)用Environment.getExternalStorageDirectory()方法來獲取外部存儲器仪或,也就是SD卡的目錄,或者使用"/mnt/sdcard/"目錄
3、使用IO流操作SD卡上的文件
注意點:手機應該已插入SD卡士骤,對于模擬器而言范删,可通過mksdcard命令來創(chuàng)建虛擬存儲卡
必須在AndroidManifest.xml上配置讀寫SD卡的權限
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
(I)文件寫操作函數(shù)
private void write(String content) {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) { // 如果sdcard存在
File file = new File(Environment.getExternalStorageDirectory()
.toString()
+ File.separator
+ DIR
+ File.separator
+ FILENAME); // 定義File類對象
if (!file.getParentFile().exists()) { // 父文件夾不存在
file.getParentFile().mkdirs(); // 創(chuàng)建文件夾
}
PrintStream out = null; // 打印流對象用于輸出
try {
out = new PrintStream(new FileOutputStream(file, true)); // 追加文件
out.println(content);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (out != null) {
out.close(); // 關閉打印流
}
}
} else { // SDCard不存在,使用Toast提示用戶
Toast.makeText(this, "保存失敗拷肌,SD卡不存在到旦!", Toast.LENGTH_LONG).show();
}
}
II)文件讀操作函數(shù)
private String read() {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) { // 如果sdcard存在
File file = new File(Environment.getExternalStorageDirectory()
.toString()
+ File.separator
+ DIR
+ File.separator
+ FILENAME); // 定義File類對象
if (!file.getParentFile().exists()) { // 父文件夾不存在
file.getParentFile().mkdirs(); // 創(chuàng)建文件夾
}
Scanner scan = null; // 掃描輸入
StringBuilder sb = new StringBuilder();
try {
scan = new Scanner(new FileInputStream(file)); // 實例化Scanner
while (scan.hasNext()) { // 循環(huán)讀取
sb.append(scan.next() + "\n"); // 設置文本
}
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (scan != null) {
scan.close(); // 關閉打印流
}
}
} else { // SDCard不存在,使用Toast提示用戶
Toast.makeText(this, "讀取失敗巨缘,SD卡不存在添忘!", Toast.LENGTH_LONG).show();
}
return null;
}
五、總結的一些使用代碼:
常用存儲:
小的數(shù)據(jù)體若锁,參數(shù)搁骑,值(存儲在shared_prefs)
網(wǎng)絡數(shù)據(jù)json(這種數(shù)據(jù)一般不大,存儲在文件中file(.txt等等) )
圖片又固、音樂仲器、視頻(建議數(shù)據(jù)較大的存儲在SD卡中,圖片(有框架的用框架))
(一)小的數(shù)據(jù)(SharedPrefs)
工具類
public class AppConfig {
private static AppConfig appConfig;
private SharedPreferences preferences;
/**
* App根目錄.
*/
public String APP_PATH_ROOT;
private AppConfig() {
preferences = MyApplication.getInstance().getSharedPreferences("test", Context.MODE_PRIVATE);
APP_PATH_ROOT = FileUtil.getRootPath(MyApplication.getInstance()).getAbsolutePath() + File.separator +
"test";
}
public synchronized static AppConfig getInstance() {
if (appConfig == null)
appConfig = new AppConfig();
return appConfig;
}
/*
public void initialize() {
IOUtils.createFolder(APP_PATH_ROOT);
}*/
public void putInt(String key, int value) {
preferences.edit().putInt(key, value).commit();
}
public int getInt(String key, int defValue) {
return preferences.getInt(key, defValue);
}
public void putString(String key, String value) {
preferences.edit().putString(key, value).commit();
}
public String getString(String key, String defValue) {
return preferences.getString(key, defValue);
}
public void putBoolean(String key, boolean value) {
preferences.edit().putBoolean(key, value).commit();
}
public boolean getBoolean(String key, boolean defValue) {
return preferences.getBoolean(key, defValue);
}
public void putLong(String key, long value) {
preferences.edit().putLong(key, value).commit();
}
public long getLong(String key, long defValue) {
return preferences.getLong(key, defValue);
}
public void putFloat(String key, float value) {
preferences.edit().putFloat(key, value).commit();
}
public float getFloat(String key, float defValue) {
return preferences.getFloat(key, defValue);
}
}
(二)文件存儲——網(wǎng)絡數(shù)據(jù)(string-->txt)
存儲數(shù)據(jù)
/**
* 存儲文件:.txt
*
* @param fileName 文件名稱
* @param content 存儲的文件內(nèi)容
*/
public static void wirteCache(String fileName, String content) {
//設置緩存
File file = new File(MyApplication.getInstance().getCacheDir(), fileName + ".txt");
if (file.exists()) {
boolean isdelete = file.delete();
if (isdelete) {
Log.e("delete", "success");
}
} else {
byte[] bytes = content.getBytes();
FileOutputStream output = null;
try {
output = new FileOutputStream(file);
output.write(bytes, 0, bytes.length);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
讀取數(shù)據(jù)
/**
* 讀取緩存數(shù)據(jù)
*
* @param fileName
* @return
*/
public static String readCache(String fileName) {
String result = null;
// 讀取文件
File file = new File(MyApplication.getInstance().getCacheDir() + File.separator
+ fileName + ".txt");
if (file.exists()) {
FileInputStream in = null;
try {
in = new FileInputStream(file);
byte[] buffer;
buffer = new byte[in.available()];
int count = 0;
while ((count = in.read(buffer)) > 0) {
result = new String(buffer);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} else {
//不存在緩存
return "";
}
return result;
}
(三)文件存儲——圖片仰冠,音樂乏冀,視頻
存儲
/**
* 文件緩存策略
*
* @param url 文件路徑
* @param fileName 文件名稱
* @param fileFormat 文件格式
*/
public static void downFile(String url, String fileName, String fileFormat) {
try {
String path = "";
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
//判斷sd卡是否存在,不存在洋只,存儲在應用內(nèi)部
path = Environment.getExternalStorageDirectory() + "/";
Log.e(TAG, "Storage file");
} else {
path = MyApplication.getInstance().getFilesDir() + "/";
Log.e(TAG, "APP file");
}
File fileDir = new File(path + "test");
if (!fileDir.exists()) {
fileDir.mkdir();
}
File file = new File(fileDir.getAbsolutePath() + "/" + fileName + "." + fileFormat);
if (file.exists()) {
} else {
URL myURL = new URL(url);
URLConnection conn = myURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
int fileSize = conn.getContentLength();
if (fileSize <= 0)
throw new RuntimeException("can not know the file`s size");
if (is == null)
throw new RuntimeException("stream is null");
FileOutputStream fos = new FileOutputStream(file.getPath());
byte buf[] = new byte[1024];
while (true) {
// 循環(huán)讀取
int numread = is.read(buf);
if (numread == -1) {
break;
}
fos.write(buf, 0, numread);
}
try {
is.close();
} catch (Exception ex) {
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
讀取
/**
* 獲取文件地址
*
* @param fileName 文件名稱
* @param fileFormat 文件格式
* @return
*/
public static String getDownFilePath(String fileName, String fileFormat) {
String path = "";
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
//判斷sd卡是否存在煤辨,不存在,存儲在應用內(nèi)部
path = Environment.getExternalStorageDirectory() + "/";
} else {
path = MyApplication.getInstance().getFilesDir() + "/";
Log.e(TAG, "cache file");
}
// 讀取文件
File file = new File(path + "test" + File.separator
+ fileName + "." + fileFormat);
if (file.exists()) {
return file.getAbsolutePath();
} else {
return "";
}
}