JavaSE多线程下载的实现

本文中主要提供的是java多线程下载文件方案,以及java多线程将临时进度保存到文件,多线程断点续传的实现;

1、多线程下载
2、将下载进度保存到临时文件,多线程的断定续传

1、多线程下载
本例中首先在Tomcat服务器中的WEBAPP/ROOT/文件夹下面放置了SoftwareOffer.exe的二进制可执行文件,如果放置图片的话,中间数据如果出错,不容易用肉眼识别,但是如果是二进制文件的话,如果中间任何二进制的一位数据出错,必然造成二进制可执行文件无法运行!所以测试选择二进制可执行文件比较妥当!
代码如下:

  • MultiDownloader.java
import java.net.HttpURLConnection;
import java.net.URL;
/** * 多线程下载器 * @author YQ */
public class MultiDownloader {

    //总线程数
    private final static int totalThreadCount = 3;

    @SuppressWarnings("unused")
    public static void main(String[] args) throws Exception {
        System.out.println("多线程下载器");
        URL url = new URL("http://192.168.1.102:8080/SoftwareOffer.exe");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        int code = conn.getResponseCode();
        if(code == 200) {
            int length = conn.getContentLength();
            System.out.println("服务器资源文件长度:"+length);
            int blockSize = length / 3;//服务器资源等分为三份,每一份的大小相同
            System.out.println("资源文件每一份的到小:"+blockSize);

            for(int threadid = 0;threadid < totalThreadCount;threadid++) {
                int startPosition = threadid * blockSize;
                int endPosition = (threadid+1) * blockSize - 1;

                if(threadid == (totalThreadCount - 1)) {
                    endPosition = length - 1;
                }
                System.out.println("线程:" + threadid + "下载范围:" + startPosition + "~" + endPosition);

                byte[] buffer = new byte[blockSize];
            }

        }
    }

}

2、将下载进度保存到临时文件,多线程的断定续传
本例中同样在Tomcat服务器中的WEBAPP/ROOT/文件夹下面放置了SoftwareOffer.exe的二进制可执行文件;

  • DemoDownLoad.java
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/** * 将下载进度保存到临时文件 * 多线程的断定续传 * @author YQ * */

public class DemoDownLoad {
    static String path = "http://192.168.1.102:8080/SoftwareOffer.exe";
    static int threadCount = 3;
    static int finishedThread = 0;
    public static void main(String[] args) {
        //发送http请求,拿到目标文件的长度
        try {
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(8000);
            conn.setReadTimeout(8000);

            if(conn.getResponseCode() == 200) {
                //获取长度
                int length = conn.getContentLength();//算出进程的开始位置和结束位置

                //创建临时文件
                File file = new File(getNameFormPath(path));
                //临时文件的使用
                RandomAccessFile raf = new RandomAccessFile(file,"rwd");
                //设置临时文件的大小与目标文件相互一致
                raf.setLength(length);
                raf.close();
                //计算每一个线程下载的区间
                int size = length / threadCount;

                for (int id=0;id < threadCount;id++) {
                    int startIndex = id * size;
                    int endIndex = (id + 1) * size - 1;
                    if(id == threadCount - 1) {
                        endIndex = length - 1;
                    }
                    System.out.println("线程" + id + "下载区间" + startIndex + "-" + endIndex);
                    new DownLoadThread(id, startIndex, endIndex).start();
                }
            }
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static String getNameFormPath(String path) {
        int index = path.lastIndexOf("/");
        return path.substring(index + 1);
    }
}

class DownLoadThread extends Thread {

    int threadId;
    int startIndex;
    int endIndex;

    public DownLoadThread(int threadId, int startIndex, int endIndex) {
        super();
        this.threadId = threadId;
        this.startIndex = startIndex;
        this.endIndex = endIndex;
    }

    @Override
    public void run() {
        //发送Http请求,三次下载则是需要三次下载请求
        try {
            File fileProgress = new File(threadId+".txt");
            int lastProgress = 0;
            if(fileProgress.exists()) {
                //读取进度临时文件中内容
                FileInputStream fis = new FileInputStream(fileProgress);
                BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                //得到上一次的下载进度数据
                lastProgress = Integer.parseInt(br.readLine());
                //改变下载开始位置,上一次下过的文件,这一次就不再进行请求
                startIndex += lastProgress;
                //进度临时文件的输入流必须关闭
                fis.close();
            }

            URL url = new URL(DemoDownLoad.path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(8000);
            conn.setReadTimeout(8000);

            //设置请求数据的区间
            conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);

            //请求部分数据成功的响应码是206
            if(conn.getResponseCode() == 206) {
                InputStream is = conn.getInputStream();
                byte[] bytes = new byte[1024];
                int len = 0;
                File file = new File(DemoDownLoad.getNameFormPath(DemoDownLoad.path));
                RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                //设置写入文件的开始位置
                raf.seek(startIndex);
                //当前线程下载的总进度
                int total = lastProgress;
                while((len = is.read(bytes)) != -1) {
                    raf.write(bytes,0,len);
                    total += len;
                    System.out.println("线程"+threadId+"下载了:"+total);
                    //创建一个文本临时文件,保存下载进度
                    RandomAccessFile rafProgress = new RandomAccessFile(fileProgress, "rwd");
                    //每次下载1024个字节,就马上把1024写入文本的临时文件
                    rafProgress.write((total+"").getBytes());
                    rafProgress.close();
                }
                raf.close();
                System.out.println("线程"+threadId+"下载完成");

                DemoDownLoad.finishedThread++;
                //首先必须要保证三条线程全部都下载完毕才可以删除
                synchronized (DemoDownLoad.path) {
                    if(DemoDownLoad.finishedThread == 3) {
                        //可能会出现线程不安全
                        for (int i=0;i<DemoDownLoad.finishedThread;i++) {
                            File f = new File(i+".txt");
                            f.delete();
                        }
                        DemoDownLoad.finishedThread = 0;
                    }
                }
            }

        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

你可能感兴趣的:(java,java,多线程,se)