多线程下载之断点续传采用随机文件读取流,HttpConnection实现

/**
*
*/
package com.l000phone.multithreaddown.advanced;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
* Description: 多线程从服器端下载资源演示(网络出现异常,需要进行断点续传)

* Copyright (c) , 2016, Jansonxu

* This program is protected by copyright laws.

* Program Name:Download.java

* Date: 2016-2-16
*
* @author 李阳
* @version : 1.0
*/
public class AdvancedDownload {

/**
 * @param args
 */
public static void main(String[] args) {
    // 1、在客户端获得服务器资源的长度,根据此长度在客户端创建一个临时文件
    try {
        URL url = new URL(
                "http://localhost:8080/ServerSide/file/VNC-5.1.1-Windows.exe");

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
            int resLen = conn.getContentLength();
            System.out.println("要下载资源的长度是:" + resLen);

            RandomAccessFile raf = new RandomAccessFile(new File(
                    "download/VNC-5.1.1-Windows.exe"), "rwd");// 创建临时文件

            raf.setLength(resLen);
            raf.close();// 关闭资源

            // 2、获得每个线程下载资源的开始和结束位置
            // 3、开启多个线程从服务其下载资源,直到所有的线程执行完毕
            int blockSize = resLen / 3;// 每个线程平均下载的长度

            AdvancedDownload outer = new AdvancedDownload();// 外部类对象

            // 创建文件对象(记录各个子线程下载的最终结果)
            File threadDownadStatusFile = new File(
                    "download/finalStauts.txt");
            if (!threadDownadStatusFile.exists()) {
                threadDownadStatusFile.createNewFile();
            }

            for (int threadId = 1; threadId <= 3; threadId++) {
                // ①开始位置
                int startPos = (threadId - 1) * blockSize;

                // ②结束位置
                int endPos = threadId * blockSize - 1;

                if (threadId == 3) {
                    endPos = resLen - 1;
                }
                // ③启动子线程下载
                outer.new DownloadSonThread(startPos, endPos, url,
                        threadId, threadDownadStatusFile).start();
            }

        }

    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

}

/**
 * 资源下载子线程
 */
private class DownloadSonThread extends Thread {
    private int startPos;
    private int endPos;
    private URL url;
    private int threadId;
    private File threadDownadStatusFile;

    public DownloadSonThread(int startPos, int endPos, URL url,
            int threadId, File threadDownadStatusFile) {
        super();
        this.startPos = startPos;
        this.endPos = endPos;
        this.url = url;
        this.threadId = threadId;
        this.threadDownadStatusFile = threadDownadStatusFile;
    }

    @Override
    public void run() {
        // ①获得连接实例
        try {
            HttpURLConnection conn = (HttpURLConnection) url
                    .openConnection();

            // 读取线程字节数记录文件中的数据,作为开始线程下载的开始位置
            File file = new File("download/" + threadId + ".txt");
            if (file.exists()) {
                BufferedReader br = new BufferedReader(new FileReader(file));
                String startPosRecord = br.readLine();
                startPos = Integer.parseInt(startPosRecord);
                br.close();
            }

            // ②设置连接的属性为下载部分资源
            conn.setRequestProperty("Range", "bytes=" + startPos + "-"
                    + endPos);

            System.out.println("来自服务器端的状态码:" + conn.getResponseCode());

            // ③从服务器获取资源,填充本地客户端的临时文件
            if (conn.getResponseCode() == 206) {// 206:服务器端的资源是属于分段下载的、200:服务端所有的资源都发送给了客户端
                // a)获得网络字节输入流
                InputStream is = conn.getInputStream();
                byte[] b = new byte[1024];
                int len = 0;

                // b)将流中的数据写入到本地临时文件中

                RandomAccessFile raf = new RandomAccessFile(new File(
                        "download/VNC-5.1.1-Windows.exe"), "rwd");// 向临时文件中写入数据
                raf.seek(startPos);

                int totalBytes = startPos;// 当前线程已经下载的字节数
                while ((len = is.read(b)) != -1) {
                    // seek移动指针偏移量,写入数据
                    raf.write(b, 0, len);
                    totalBytes += len;// 累加目前已经下载的字节数
                    RandomAccessFile nowRecordLenFile = new RandomAccessFile(
                            new File("download/" + threadId + ".txt"),
                            "rwd");
                    nowRecordLenFile.write((totalBytes + "").getBytes());
                    nowRecordLenFile.close();
                }
                raf.close();
                System.out.println("线程" + threadId + "下载资源完毕....");
                FileWriter fw = new FileWriter(threadDownadStatusFile, true);
                fw.write(threadId + "over");
                fw.close();
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 读取文件中的内容,若发现内容匹配:
            // 内容.contains("thread1over") 并且 内容.contains("thread2over") 并且
            // 内容.contains("thread3over")
            // 就删除各个临时文件
            BufferedReader br = null;
            try {
                br = new BufferedReader(new FileReader(
                        threadDownadStatusFile));
                String finalResultInfo = br.readLine();
                if (finalResultInfo.contains("1over")
                        && finalResultInfo.contains("2over")
                        && finalResultInfo.contains("3over")) {
                    for (int threadId = 1; threadId <= 3; threadId++) {
                        new File("download/" + threadId + ".txt").delete();
                    }

                    br.close();

                    new File("download/finalStauts.txt").delete();

                    System.out.println("恭喜!所有临时文件都已经删除掉了哦!...");
                }

            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }
}

}

你可能感兴趣的:(多线程,断点续传-文件流)