多线程下载

服务器上有10个字节的数据,如果目前我们有三条线程从服务器上取数据,他们分别是:
线程0、1、2,
 
2)那么我们每条线程负责下载的数据量是多少呢?

每条线程下载的数据量是:

int block = 文件长度%N == 0 ?文件长度/N : 文件长度/N+1;


eg:

那么着10个字节的数据用三条线程来下载,每条线程负责下载的数据量为:

int block = 10%3 == 0? 10/3 :10/3+1;
根据公式计算计算,每条线程负责下载的数据量是:10/3+1 = 3+1 =4;
0、1线程负责下载的数据量分别是4,2线程负责下载的数据量是2,因为下载道10的长度的时候就停止了;
 
3)开启多线程分别从网络文件的不同位置下载该文件,并从本地文件的相同位置写入数据,要计算出每条线程从网络文件的什么位置开始下载数据,到什么位置结束。
 
每条线程开始下载的位置是:

int start = threadId * block

eg:那么第一条线程id=0,那么开始下载的位置便是:0*4 = 0;第二条线程的id=1,则其开始下载的位置是1*4 = 4;第三条线程开始下载的位置为:2*4 = 8;

 
每条线程下载结束的位置是:
int end = (threadId+1)*block—1

那么结束的位置分别为:3,7,10,因为最后一条线程下载到10的时候,没有资源下载便会停止。

多线程下载的核心代码如下:


import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

public class BreakPointDownload {

    /**
     * @param args
     * @throws MalformedURLException
     */
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        String path = "";
        new BreakPointDownload().download(path, 3);

    }

    /**
     * use:下载文件
     *
     * @param path
     * @param i
     * @throws Exception
     */
    private void download(String path, int threadSize) throws Exception {
        // TODO Auto-generated method stub
        URL url = new URL(path);
        HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
        conn.setReadTimeout(5000);
        conn.setRequestMethod("GET");

        if (conn.getResponseCode() == 200) {
            int contentLength = conn.getContentLength();// 获取文件的长度
            File file = new File(getFileName(path));
            RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");// 在本地生成一个和网络上文件长度相等的文件
            accessFile.setLength(contentLength);
            accessFile.close();

            // 计算每条线程负责下载的数据量
            int block = contentLength % threadSize == 0 ? contentLength
                    / threadSize : contentLength / threadSize + 1;
            for (int threadId = 0; threadId < threadSize; threadId++) {
                new DownloadThread(threadId, block, url, file).start();
            }
        } else {
            System.out.println("文件下载失败!");
        }

    }

    private class DownloadThread extends Thread {

        private int threadId;
        private int block;
        private URL url;
        private File file;

        public DownloadThread(int threadId, int block, URL url, File file) {
            // TODO Auto-generated constructor stub
            this.threadId = threadId;
            this.block = block;
            this.url = url;
            this.file = file;
        }

        @Override
        public void run() {
            int start = threadId * block;// 计算该线程从网络文件的什么位置开始下载
            int end = (threadId + 1) * block - 1;// 该线程下载结束的位置

            try {
                //单条线程下载数据
                RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");// 在本地生成一个和网络上文件长度相等的文件
                accessFile.seek(start);

                // 请求网络文件的某一个区域的数据
                HttpsURLConnection conn = (HttpsURLConnection) url
                        .openConnection();
                conn.setReadTimeout(5000);
                conn.setRequestMethod("GET");
                conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
                if (conn.getResponseCode() == 206) {//注意:在多线程下载的时候判断码不是200 而是 206
                    InputStream in = conn.getInputStream();
                    byte[] buffer = new byte[1024];
                    int lenght = 0;
                    while( (lenght = in.read(buffer)) != -1){
                        accessFile.write(buffer, 0, lenght);
                    }
                    accessFile.close();
                    in.close();
                            
                }
                System.out.println("第"+threadId+"条下载完毕!");

            } catch (Exception e) {
                e.printStackTrace();
            }
            super.run();
        }

    }

    private String getFileName(String path) {
        
        return path.substring(path.lastIndexOf("/") + 1);
    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值