Java实现多线程下载和断点续传

来源:互联网 发布:安徒生童话 知乎 编辑:程序博客网 时间:2024/05/22 00:37

java的多线程下载能够明显提升下载的速度,平时我们用的迅雷软件之所以能够下载那么快,就是使用了多线程;当用户在下载的过程中,有断电或断网的可能,当用户再次点击下载时,应该让用户接着原来的进度进行下载,这可以节约用户的流量,所以要用到断点续传的功能。下面是通过Java代码实现多线程下载和断点续传的详细代码。

1,创建一个类,用于文件的下载

<pre name="code" class="java"><span style="font-size:18px;">package com.edu.thread;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.InputStream;import java.io.InputStreamReader;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;public class MultiDownload2 {static String path = "http://localhost:8080/wlan.zip";//开启线程的数量static int threadCount = 6;//下载结束的线程数static int threadFinished = 0;public static void main(String[] args) {try {URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);conn.setReadTimeout(5000);//此时只是确定和服务器建立了连接,但并没有开始下载任务if (conn.getResponseCode()==200) {//拿到文件的长度int length = conn.getContentLength();//指定文件路径和文件名File file = new File("d://文件测试", getFileName(path));//创建随机存储文件大小,为了建立一个和源文件大小相同的存储区间RandomAccessFile raf = new RandomAccessFile(file, "rwd");//设置临时文件的大小,和服务器文件一模一样raf.setLength(length);//计算每个线程下载的字节数int size = length / threadCount;//计算三个线程下载的开始位置和结束位置for (int i = 0; i < threadCount; i++) {int startIndex = i * size;int endIndex = (i + 1) * size-1;//如果是最后一个线程,要把结尾读完if (i == threadCount-1) {//length从0开始读,所以length-1表示最后一个字节endIndex = length-1;}//打印三个线程的开始与结束位置System.out.println("线程"+i+"的开始和结束位置:"+startIndex+"----"+endIndex);//开启线程,传入线程ID,下载的开始位置和下载的结束位置new DownloadThread(i, startIndex, endIndex).start();;}}} catch (Exception e) {e.printStackTrace();}}/** 获取文件名*/public static String getFileName(String path){int index=path.lastIndexOf("/");return path.substring(index + 1);}}</span>

2,创建另一个类,用于开启子线程

<pre name="code" class="java"><span style="font-size:18px;">package com.edu.thread;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.InputStream;import java.io.InputStreamReader;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;//新开启一个线程,用于完成下载任务class DownloadThread extends Thread{int thredId;int startIndex;int endIndex;public DownloadThread(int thredId, int startIndex, int endIndex) {super();this.thredId = thredId;this.startIndex = startIndex;this.endIndex = endIndex;}public void run() {try {//下载进度文件保存的路径和文件名File progressFile = new File("d://文件测试",(thredId + ".txt"));//判断保存下载进度的临时文件是否存在,以便确定下载的开始位置if (progressFile.exists()) {FileInputStream fis = new FileInputStream(progressFile);BufferedReader bReader = new BufferedReader(new InputStreamReader(fis));//拿到临时文件中保存的数据,并把此数据设置为新的开始位置int text = Integer.parseInt(bReader.readLine());startIndex = text;fis.close();}System.out.println("线程"+thredId+"的最终开始下载位置是:"+startIndex);URL url = new URL(MultiDownload2.path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");conn.setConnectTimeout(5000);conn.setReadTimeout(5000);//设置请求数据的范围conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);//建立连接,状态码206表示请求部分数据成功,此时开始下载任务if (conn.getResponseCode()==206) {InputStream is = conn.getInputStream();//指定文件名和文件路径File file = new File(MultiDownload2.getFileName(MultiDownload2.path) );int len = 0;byte [] b = new byte[1024];//三个线程各自创建自己的随机存储文件RandomAccessFile raf = new RandomAccessFile(file, "rwd");//设置数据从哪个位置开始写入数据到临时文件raf.seek(startIndex);//设置当前线程下载的总字节数int total = 0;long start = System.currentTimeMillis();//当下载意外停止时,记录当前下载进度int currentPosition = startIndex;while ((len=is.read(b))!=-1) {raf.write(b,0,len);//打印当前线程下载的总字节数total += len;/*** 实现断点续传的功能*///RandomAccessFile主要用来存放下载的临时文件,可以用FileOutputStream代替RandomAccessFile rafProgress = new RandomAccessFile(progressFile, "rwd");//再次下载时的开始位置currentPosition = startIndex + total;//把下载进度写进rafProgress临时文件,下一次下载时,就以这个值作为新的startIndexrafProgress.write((currentPosition + "").getBytes());//关流rafProgress.close();System.out.println("线程"+thredId+"已经下载了"+total);}raf.close();long end = System.currentTimeMillis();//打印线程下载文件用时System.out.println("线程"+thredId+"下载文件用时"+(end-start)+"ms");//打印线程的结束System.out.println("线程:"+thredId+" 下载结束了 !!!");//下载结束后,删除所有的临时文件MultiDownload2.threadFinished ++;//使用同步语句块,保证线程的安全性synchronized (MultiDownload2.path) {//如果这个条件成立,说明所有的线程下载结束if (MultiDownload2.threadFinished == MultiDownload2.threadCount) {for (int i = 0; i < MultiDownload2.threadCount; i++) {//删除三个线程产生的临时文件File temp = new File("d://文件测试", i + ".txt");temp.delete();}//保证三个线程的临时文件同时被删除MultiDownload2.threadFinished = 0;}}}} catch (Exception e) {e.printStackTrace();}}}</span>

0 0
原创粉丝点击