Java多執行緒使用執行緒池實現檔案下載
阿新 • • 發佈:2018-11-26
多執行緒下載原理:
1、基本思路是將檔案分段切割、分段傳輸、分段儲存。
2、分段切割用到HttpUrlConnection物件的setRequestProperty(“Range”, “bytes=” + start + “-” + end)方法。
3、分段傳輸用到HttpUrlConnection物件的getInputStream()方法。
4、分段儲存用到RandomAccessFile的seek(int start)方法。
5、建立指定長度的執行緒池,迴圈建立執行緒,執行下載操作。
程式碼設計:
總共程式碼分為三個類,DownloadWithRange 、DownloadFileWithThreadPool和test。其中test相當於實際使用中框架中的controll層程式碼。DownloadWithRange 實現Runnable介面,DownloadFileWithThreadPool主要是執行緒池操作和呼叫DownloadWithRange 類。test就是一個測試類。
package file; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; /** * 2018/11/21. */ public class DownloadWithRange implements Runnable { private String urlLocation; private String filePath; private long start; private long end; DownloadWithRange(String urlLocation, String filePath, long start, long end) { this.urlLocation = urlLocation; this.filePath = filePath; this.start = start; this.end = end; } @Override public void run() { try { HttpURLConnection conn = getHttp(); conn.setRequestProperty("Range", "bytes=" + start + "-" + end); File file = new File(filePath); RandomAccessFile out = null; if (file != null) { out = new RandomAccessFile(file, "rwd"); } out.seek(start); InputStream in = conn.getInputStream(); byte[] b = new byte[1024]; int len = 0; while ((len = in.read(b)) != -1) { out.write(b, 0, len); } in.close(); out.close(); } catch (Exception e) { e.getMessage(); } } public HttpURLConnection getHttp() throws IOException { URL url = null; if (urlLocation != null) { url = new URL(urlLocation); } HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(5000); conn.setRequestMethod("GET"); return conn; } } package file; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.util.concurrent.Executor; import java.util.concurrent.Executors; /** * 2018/11/21. */ public class DownloadFileWithThreadPool { public void getFileWithThreadPool(String urlLocation,String filePath, int poolLength) throws IOException { Executor threadPool = Executors.newFixedThreadPool(poolLength); long len = getContentLength(urlLocation); System.out.println("檔案大小:"+len); for(int i=0;i<poolLength;i++) { long start=i*len/poolLength; long end = (i+1)*len/poolLength-1; if(i==poolLength-1) { end =len; } DownloadWithRange download=new DownloadWithRange(urlLocation, filePath, start, end); threadPool.execute(download); try { Thread.sleep(2); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static long getContentLength(String urlLocation) throws IOException { URL url = null; if (urlLocation != null) { url = new URL(urlLocation); } HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(5000); conn.setRequestMethod("GET"); long len = conn.getContentLength(); return len; } } package file; import java.io.IOException; public class test { public static void main(String [] args){ DownloadFileWithThreadPool dfw = new DownloadFileWithThreadPool(); try { // "http://10.128.99.13"+"/usr/ulitech/dataroot/scadadata/2018/11.tar.gz" long startTime=System.currentTimeMillis(); dfw.getFileWithThreadPool("http://10.128.99.13:8080"+"/sysobjects/sysobjects.db","E:/1/11.rar",10); long endTime=System.currentTimeMillis(); System.out.println("耗費時間: "+(endTime-startTime)+" ms"); System.out.println("下載成功!"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
思考:
1.對於下載路徑處理?路徑的有效性?
2.多個小檔案的效率?
後續進行分析和解答。。。。。。。。。。