原理:获取目标文件的大小,在本地创建一个相同大小的文件,并计算每个线程需要下载的起始位置及大小,然后分配至每个线程独立下载,全部下载完毕则自动合并.
实现步骤
1. 查看并计算目标文件的大小
1 2 3 4 5 6 7 8
| URL url = new URL(mPath); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); int code = connection.getResponseCode(); if (code == 200) { int length = connection.getContentLength(); System.out.println("文件总长度为:" + length);
|
2. 设置目标文件在本地的映射
1 2 3 4
| RandomAccessFile raf = new RandomAccessFile( Environment.getExternalStorageDirectory(). getAbsolutePath()+"/"+getDownlaodName(mPath), "rw"); raf.setLength(length);
|
3. 开启子线程并分配下载任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| int blokeSize = length / mTotalCount; System.out.println("每一块大小为:" + blokeSize); runningThreadCount = mTotalCount; for (int threadid = 0; threadid < mTotalCount; threadid++) { int startPosition = threadid * blokeSize; int endPosition = (threadid + 1) * blokeSize - 1; if (threadid == mTotalCount - 1) { endPosition = length - 1; } System.out.println("线程编号:" + threadid + "" + ",下载范围:" + startPosition + "~~" + endPosition); new DownloadThread(threadid, startPosition, endPosition).start();
|
4. 子线程中的具体逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| public void run() { System.out.println("线程"+threadid+"开始运行了"); try{ File finfo=new File(Environment .getExternalStorageDirectory() .getAbsolutePath() +"/"+mTotalCount + getDownlaodName(mPath)+threadid+".txt"); if (finfo.exists()&&finfo.length()>0) { FileInputStream fis=new FileInputStream(finfo); BufferedReader br=new BufferedReader( new InputStreamReader(fis)); String lasrposition=br.readLine(); int intlastposition=Integer.parseInt(lasrposition); lastLoadSize=intlastposition-startPosition; startPosition=intlastposition; fis.close(); } URL url=new URL(mPath); HttpURLConnection conn=(HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); System.out.println("线程实际下载:"+threadid+",范围:"+startPosition +"~~"+endPosition); conn.setRequestProperty("Range", "bytes=" +startPosition+"-"+endPosition); int code=conn.getResponseCode(); if (code==206) { InputStream is=conn.getInputStream(); RandomAccessFile raf=new RandomAccessFile( Environment.getExternalStorageDirectory().getAbsolutePath() +"/"+getDownlaodName(mPath), "rw"); raf.seek(startPosition); byte[] buffer=new byte[1024*1024]; int len=-1; int total=0; while ((len=is.read(buffer))!=-1) { raf.write(buffer,0,len); total+=len; RandomAccessFile inforaf=new RandomAccessFile( Environment.getExternalStorageDirectory().getAbsolutePath() +"/"+mTotalCount +getDownlaodName(mPath)+threadid+".txt","rwd"); inforaf.write(String.valueOf(startPosition+total).getBytes()); inforaf.close(); } is.close(); raf.close(); System.out.println("线程"+threadid+"下载完毕");
} }catch(Exception e){ e.printStackTrace(); }finally{ synchronized (MainActivity.class) { runningThreadCount--; if (runningThreadCount<=0) { System.out.println("多线程下载完毕"); for (int i = 0; i <mTotalCount ; i++) { File f=new File(Environment.getExternalStorageDirectory() .getAbsolutePath() +"/"+mTotalCount +getDownlaodName(mPath) +i+".txt"); System.out.println(f.delete()); endTime=System.currentTimeMillis(); } System.out.println("结束时间:"+endTime); System.out.println("总共花费:" +(endTime-startTime)/1000+"秒"); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), "总共花费:"+(endTime-startTime)/1000+"秒", Toast.LENGTH_SHORT).show(); } }); } } } }
|
备注:如果不使用断点下载,只需要将判断和存储历史下载信息的逻辑删除即可。