package cn.lei.util;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;import android.app.ProgressDialog;import android.os.Environment;import android.widget.ProgressBar;public class DownloadUtil { private String path; private int threadnumber; private String target; private int process=0; private int totalsize; //标记是否停止下载 private boolean isstop = false; int blocksize; File file; ProgressDialog pb; public DownloadUtil(String path, String target, int threadnumber, ProgressDialog pb) { this.path = path; this.target = target; this.threadnumber = threadnumber; this.pb = pb; } public int getProcess() { return process; } public int getTotalsize() { return totalsize; } public File startDownload() throws IOException { isstop = false; if (path == null) { return null; } //连接服务器查询文件字节数, URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(5000); conn.setRequestMethod("GET"); totalsize = conn.getContentLength(); //设置processbar,或者processDialog的Max pb.setMax(totalsize); //得到下载文件名称 String finame = path.substring(path.lastIndexOf("/") + 1); //在本地创建文件 file = createFile(target, finame);// 设置分配每个线程下载的大小 if (totalsize % threadnumber == 0) { blocksize = totalsize / threadnumber; } else { blocksize = totalsize / threadnumber + 1; } //开启线程下载 for (int i = 0; i < this.threadnumber; i++) { new DownloadThread(i).start(); } return file; } private File createFile(String target, String finame) {// 判断SDCARD是否可用 File f = null; if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ f = new File(Environment.getExternalStorageDirectory(), target); if (!f.exists()) { f.mkdirs(); } }else{// 或者保存到ROM throw new RuntimeException(); } File ff = new File(f, finame); return ff; } public void stopDownload() { this.isstop = true; } class DownloadThread extends Thread { private int threadid; public DownloadThread(int threadid) { this.threadid = threadid; } @Override public void run() { try {// 已线程ID命名文件,保存下载进度信息 File temp = new File(Environment.getExternalStorageDirectory(), target + threadid + ".temp"); URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(5000); conn.setRequestMethod("GET");// 计算将请求的开始字节,结束字节 int startposition = threadid * blocksize; int endposition = (threadid + 1) * blocksize - 1; if (endposition > totalsize) { endposition = totalsize; }// 如果存在之前下载文件信息,调整请求 if (temp.exists()) { FileInputStream input = new FileInputStream(temp); byte[] buf = new byte[8]; int len = input.read(buf); if (len > 0) { startposition = Integer.parseInt(new String(buf, 0, len)); } input.close(); }// 设置请求 conn.setRequestProperty("Range", "bytes=" + startposition + "-"+ endposition);// 保存下载文件 RandomAccessFile accessFile = new RandomAccessFile(file, "rwd"); accessFile.seek(startposition); InputStream is = conn.getInputStream(); int leng = 0; byte[] buff = new byte[1024]; while ((leng = is.read(buff)) > 0) { if (isstop) { return; } accessFile.write(buff, 0, leng); startposition += leng;// 更新process* 的信息 synchronized (DownloadUtil.this) { process += leng; pb.setProgress(process); pb.setMessage(process+"/"+totalsize); }// 保存下载进度 FileOutputStream fos = new FileOutputStream(temp); fos.write((startposition + "").getBytes()); fos.flush(); fos.close(); } is.close(); accessFile.close(); temp.delete(); } catch (Exception e) { e.printStackTrace(); } } } }
? 期待更好的算法,更好的效率的做法.
这个保存进度的时候会频繁I/O操作,效率肯定不好.
下载大文件的时候,出现过下载进度不增加的情况.
对于较小的文件<8M,这个足以应付.