zoukankan      html  css  js  c++  java
  • 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];
        }
    }

  • 相关阅读:
    [每天解决一问题系列
    [每天解决一问题系列
    [每天解决一问题系列
    nodejs&mongo&angularjs
    [转]Express框架
    [转]Use HandleBars in Express
    10 Tips for Optimizing Your Website’s Speed
    One difference between AngularJS' $location and window.location
    Why does Http header contains "X-SourceFiles"?
    JavaScript数组常用方法
  • 原文地址:https://www.cnblogs.com/ZHONGZHENHUA/p/7076505.html
Copyright © 2011-2022 走看看