10_多线程下载_完成

接下来要创建多个线程了。

在服务端这边要通过一个请求头Range,用setRequestProperty给它传一个Range.每一个线程下载的起始位置和结束位置都是不一样的。但是正好是连在一起的。

 

 

package com.itheima.multiThreadDownload;
//import java.net.MalformedURLException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
//import java.net.URLConnection;
import java.net.URLConnection;

public class MultiThreadDownload {
     private static String path = "http://127.0.0.1:8080/FeiQ.exe";
     private static int threadCount= 3;//不搞那么多就搞三个线程.
     public static void main(String[] args) {
        //①联网获取要下载的文件长度
        try {
            URL url = new URL(path);
            //URLConnection openConnection = url.openConnection();
            HttpURLConnection openConnection = (HttpURLConnection) url.openConnection();
            openConnection.setRequestMethod("GET");
            openConnection.setConnectTimeout(10000);
            int responseCode = openConnection.getResponseCode();
            if(responseCode==200){
                //获取要下载的文件长度
                //int contentLength = openConnection.getContentLength();
                //long contentLengthLong = openConnection.getContentLengthLong();
                int contentLength = openConnection.getContentLength();
                //在本地创建一个一样的文件
                RandomAccessFile file = new RandomAccessFile(getFilename(path), "rw");//第一个叫file或者说是name(路径),第二个参数叫mode
                //名字可以通过路径去获取,截取这个路径最后一个斜杠.剩下的这个就是我要下载的文件名
                //file.setLength(contentLengthLong);//文件创建出来之后去设置文件的长度
                file.setLength(contentLength);//文件创建出来之后去设置文件的长度
                //计算每一个线程要下载多少数据
                //int blockSize = contentLengthLong/threadCount;
                int blockSize = contentLength/threadCount;
                //计算每一个线程要下载的数据范围
                for (int i = 0; i < threadCount; i++) {
                    //用i和blockSize来确定startIndex和endIndex
                    int startIndex  = i*blockSize; 
                    int endIndex = (i+1)*blockSize-1;
                    if(i==threadCount-1){
                        //说明是最后一个线程
                        endIndex = contentLength-1;
                    }
                    new DownLoadThread(startIndex, endIndex, i).run();//main是静态的方法,要求DownLoadThread也是静态的.
                }
            }
        } //catch (MalformedURLException e) {
      catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
     private static class DownLoadThread extends Thread{
            private int startIndex;
             private int endIndex;
             private int threadID;//线程的编号
         public DownLoadThread(int startIndex, int endIndex, int threadID) {
            super();
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.threadID = threadID;
        }
         @Override
        public void run() {
            // TODO Auto-generated method stub
            //super.run();
             //run方法还是要联网,拿着url向服务端请求数据.多个线程联网下载数据
             try {
                URL url =  new URL(path);
                //URLConnection openConnection = url.openConnection();
                HttpURLConnection openConnection = (HttpURLConnection) url.openConnection();
                openConnection.setRequestMethod("GET");
                openConnection.setConnectTimeout(10000);
                //设置Range头,用计算好的开始索引和结束索引到服务端请求数据
                openConnection.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);//计算出来的开始索引和结束的位置
                if(openConnection.getResponseCode()==206){
                    System.out.println("线程"+threadID+"开始下载"+startIndex);
                    InputStream inputStream = openConnection.getInputStream();
                    //通过RandomAccessFile来写对应的内容了
                    int len = -1;
                    byte[] buffer = new byte[1024];
                    RandomAccessFile file = new RandomAccessFile(getFilename(path), "rw");//文件存在的话它其实是做打开的操作,文件不存在的话是做创建
                    //这个文件咱们已经创建好了,现在咱们是要给它打开.
                    //打开之后需要注意这一步一定不要忘记 要 要 seek到startIndex位置  写入数据
                    //如果你这个seek忘了 实际上你每一个线程都是从头开始写的 三个线程都是从最开始写到了三分之一的位置
                    //把这三件数据写到了同一个位置 你的文件大小  因为咱们之前创建了一个相同大小的文件 你看起来这个大小是没问题的  但是只有前三分之一有数据
                    file.seek(startIndex);//挪到每个线程指定的位置开始去写
                    while((len=inputStream.read(buffer))!=-1){//写对应的内容了.
                        file.write(buffer,0,len);
                    }//整个while循环结束了这个文件就写完了
                    file.close();
                    System.out.println("线程"+threadID+"下载结束");
                }
            //} catch (MalformedURLException e) {
              } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
             
             
        }
     }
    private static String getFilename(String path) {
        String[] split = path.split("/");//拿斜杠去切
        
        return split[split.length-1];
    }
}

 

 

posted on 2017-06-25 12:30  绿茵好莱坞  阅读(134)  评论(0编辑  收藏  举报

导航