由於需求所至,爲了保證文件下載的完整性,需要對文件進行安全校驗,故在此簡單的實現了下DownLoadManager下載文件並伴有 安全校驗的功能
需求簡述:
1:下載文件,保證文件下載的完整性需要有MD5校驗
2:不能重複下載文件(如果有文件,就不下載)
首先是是DownLoadManager對文件的下載,單個文件的下載問題不大,關鍵是多個文件同時下載,會出現信息匹配錯亂的問題
public class FileManager { private static String sdCard = Environment.getExternalStorageDirectory().toString(); private static FileManager instance; private Context context; private static DownloadManager mDownLoadService; private static String mType; private static LongSparseArray<SourceBean> downloadQueue; private FileManager(Context context) { this.context = context; downloadQueue = new LongSparseArray<>(); } public static FileManager getInatance(Context context) { if (instance == null) { instance = new FileManager(context); } return instance; } /** * 保存文件 * * @param savePath * @param sourceBean */ public void downFile(String savePath, SourceBean sourceBean) { String name = sourceBean.getName(); String md5 = sourceBean.getMd5(); String url = sourceBean.getUrl(); File file = new File(savePath + name); if (file.exists() && md5.equals(getFileMD5(savePath + name))) { Log.i("xd----------", "文件存在,無需下載"); } else if (file.exists() && !md5.equals(getFileMD5(savePath + name))) { file.delete(); Log.i("xd----------", "文件以改變,需下載"); downloadfile(savePath, sourceBean); } else { Log.i("xd----------", "沒有文件,需下載"); downloadfile(savePath, sourceBean); } } /** * 從網絡端下載文件 * * @param savePath * @param sourceBean */ private void downloadfile(String savePath, SourceBean sourceBean) { String url = sourceBean.getUrl(); String name = sourceBean.getName(); DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); //設置下載時網絡類型 request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI|DownloadManager.Request.NETWORK_MOBILE); //下載時狀態欄是否顯示 request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN); //設置漫遊狀態下是否下載 request.setAllowedOverRoaming(true); //設置允許MediaScanner掃描 request.allowScanningByMediaScanner(); //下載文件存放的路徑--file:///storage/emulated/0/test/ mDownLoadService = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); mType = name.substring(name.length() - 4, name.length()); name = name.substring(0, name.length() - 4).concat(".temp"); Log.i("xd---", name); //根據需求改,我這邊是要下載多種類型的文件,故在此對其做了區分 switch (mType) { case ".mp3": request.setDestinationInExternalPublicDir("/test/mp3/", name); //根據每個下載id保存下載文件的信息 downloadQueue.append(mDownLoadService.enqueue(request), sourceBean); break; case ".gif": request.setDestinationInExternalPublicDir("/test/gif/", name); //根據每個下載id保存下載文件的信息 downloadQueue.append(mDownLoadService.enqueue(request), sourceBean); break; case ".ttf": request.setDestinationInExternalPublicDir("/test/ttf/", name); //根據每個下載id保存下載文件的信息 downloadQueue.append(mDownLoadService.enqueue(request), sourceBean); break; } IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE); DownLoadCompleteReceiver receiver = new DownLoadCompleteReceiver(); context.registerReceiver(receiver, intentFilter); } /** * 獲取文件路徑 * * @param path * @param md5 * @return */ public String getFile(String path, String md5) { File file = new File(path); if (!file.exists()) { return "null"; } if (!getFileMD5(path).equals(md5)) { return "null"; } return path; } /** * 獲取文件的MD5碼 * * @param path * @return * @throws IOException * @throws NoSuchAlgorithmException */ public static String getFileMD5(String path) { File file = new File(path); if (!file.exists()) { return "null"; } FileInputStream fis = null; MappedByteBuffer map = null; try { fis = new FileInputStream(path); map = fis.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length()); } catch (IOException e) { e.printStackTrace(); } MessageDigest md5 = null; try { md5 = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } md5.update(map); BigInteger bi = new BigInteger(1, md5.digest()); String value = bi.toString(16).toUpperCase(); try { fis.close(); } catch (IOException e) { e.printStackTrace(); } return value; } public static class DownLoadCompleteReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) { DownloadManager.Query query = new DownloadManager.Query(); //獲取下載的文件的所有id,並保存在一個 long[] ids = new long[downloadQueue.size()]; for (int i = 0; i < downloadQueue.size(); i++) { ids[i] = downloadQueue.keyAt(i); } query.setFilterById(ids); Cursor cursor = mDownLoadService.query(query); if (cursor != null) { while (cursor.moveToNext()) { int status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)); switch (status) { case DownloadManager.STATUS_PENDING: break; case DownloadManager.STATUS_PAUSED: break; case DownloadManager.STATUS_RUNNING: break; case DownloadManager.STATUS_SUCCESSFUL: SourceBean sourceBean = downloadQueue.get(cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_ID))); //下載文件的路徑 String filePath = cursor.getString(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_URI)); //對路徑進行編碼處理(我的路徑亂碼了) filePath = URLDecoder.decode(filePath); //由於路徑是file:///格式,故對其進行了處理 filePath = filePath.substring(7, filePath.length()); String url = sourceBean.getUrl(); String newPath = null; if (url.endsWith(".gif")) { //你要保存的文件路徑 newPath = filePath.substring(0, filePath.length() - 5).concat(".gif"); } else if (url.endsWith(".ttf") || url.endsWith("TTF")) { newPath = filePath.substring(0, filePath.length() - 5).concat(".ttf"); } else if (url.endsWith(".mp3")) { newPath = filePath.substring(0, filePath.length() - 5).concat(".mp3"); } String result = saveFile(sourceBean.getMd5(), filePath, newPath); break; case DownloadManager.STATUS_FAILED: break; } } cursor.close(); } } } } /** * 判斷文件並,保存下載文件 * * @param md5 * @param filePath * @param newPath */ private static String saveFile(String md5, String filePath, String newPath) { File file = new File(filePath); File newFile = new File(newPath); String fileMD5 = getFileMD5(filePath); if (!file.exists()) { return "null"; } else if (!fileMD5.equals(md5)) { file.delete(); return "null"; } else if (file.renameTo(newFile)) { file.delete(); return newPath; } else { file.delete(); return "null"; } } }
由於文件信息比較多,所以我自定義了一個SourseBean類來保存
public class SourceBean { private String name; private String url; private String md5; public SourceBean(String name, String url, String md5) { this.name = name; this.url = url; this.md5 = md5; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getMd5() { return md5; } public void setMd5(String md5) { this.md5 = md5; } }
下載文件建議在IntentService下進行,其也是在線程中執行的。