zoukankan      html  css  js  c++  java
  • 多线程下载

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
      
        <servlet>
            <servlet-name>downloadImage</servlet-name>
            <servlet-class>mutidownload.ImageServlet</servlet-class>
        </servlet>
        
        <servlet-mapping>
            <servlet-name>downloadImage</servlet-name>
            <url-pattern>*.download</url-pattern>
        </servlet-mapping>
        
    </web-app>
    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <title>图片下载</title>
      </head>
      
      <body>
        <div>
            <label>Tomcat</label><a href="http://localhost:8080/lf.download?url=http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-6/v6.0.53/bin/apache-tomcat-6.0.53.tar.gz">下载</a><br>
        </div>
      </body>
    </html>
    package mutidownload;
    
    import java.io.IOException;
    import java.nio.file.Path;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import mutidownload.util.DownUtil;
    
    public class ImageServlet extends HttpServlet{
        
        
        public void doGet(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
    
            String path = req.getParameter("url");
            
            System.out.println(path);
            DownUtil downUtil =new DownUtil(path, "C:\Users\111\Desktop\test", 3);
            try {
                downUtil.download();
            } catch (Exception e) {
                e.printStackTrace();
            }
            //转发
            req.getRequestDispatcher("/index.jsp").forward(req, resp);
        }
    }
    package mutidownload.util;
    
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.RandomAccessFile;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class DownUtil {
        /**
         * 被下载文件的路径
         */
        private String path;
        /**
         * 下载文件存放的目录
         */
        private String targetFilePath;  
        /**
         * 线程数量
         */
        private static int threadCount = 3;
        
        /**
         * 被下载文件的大小
         */
        private int connectionLength;
        
        /**
         * 定义下载的线程对象
         */
        private DownloadThread[] threads;
       
        /**
         * 构造方法 
         * @param path 要下载文件的网络路径
         * @param targetFilePath 保存下载文件的目录
         * @param threadCount 开启的线程数量
         */
        public DownUtil(String path, String targetFilePath, int threadCount) {
            this.path = path;
            this.targetFilePath = targetFilePath;
            this.threadCount = threadCount; 
        }
    
        /**
         * 下载文件
         */
        public void download() throws Exception{
            //连接资源
            URL url = new URL(path);
            // 打开连接
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            // 设置请求方式
            connection.setRequestMethod("GET");
            // 设置超时时间
            connection.setConnectTimeout(10000);
            // 获取响应状态码
            int code = connection.getResponseCode();
            if(code == 200){
                //获取资源大小
                connectionLength = connection.getContentLength();
                System.out.println(connectionLength);
                //在本地创建一个与资源同样大小的文件来占位
                RandomAccessFile randomAccessFile = new RandomAccessFile(new File(targetFilePath,getFileName(url)), "rw");
                randomAccessFile.setLength(connectionLength);
                /*
                 * 将下载任务分配给每个线程
                 */
                //计算每个线程理论上下载的数量
                int blockSize = connectionLength/threadCount;
                //为每个线程分配任务
                for(int threadId = 0; threadId < threadCount; threadId++){
                    //线程开始下载的位置
                    int startIndex = threadId * blockSize; 
                    //线程结束下载的位置
                    int endIndex = (threadId+1) * blockSize -1;
                    //如果是最后一个线程,将剩下的文件全部交给这个线程完成
                    if(threadId == (threadCount - 1)){  
                        endIndex = connectionLength - 1;
                    }
                    //开启线程下载
                    new DownloadThread(threadId, startIndex, endIndex).start();
                }
                  randomAccessFile.close();
            }
    
        }
        
    
    
        //下载的线程
        private class DownloadThread extends Thread{
    
            private int threadId;
            private int startIndex;
            private int endIndex;
             
            public DownloadThread(int threadId, int startIndex, int endIndex) {
                this.threadId = threadId;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
            }
            
            @Override
            public void run() {
                System.out.println("线程"+ threadId + "开始下载");
                try {
                    //分段请求网络连接,分段将文件保存到本地.
                    URL url = new URL(path);
                    //加载下载位置的文件
                    File downThreadFile = new File(targetFilePath,"downThread_" + threadId+".dt");
                    RandomAccessFile downThreadStream = null;
                    //如果文件存在
                    if(downThreadFile.exists()){
                        downThreadStream = new RandomAccessFile(downThreadFile,"rwd");
                        String startIndex_str = downThreadStream.readLine();
                        this.startIndex = Integer.parseInt(startIndex_str);//设置下载起点
    
                    }else{
                        downThreadStream = new RandomAccessFile(downThreadFile,"rwd");
                    }
                    // 打开连接
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(10000);
    
                    //设置分段下载的头信息。  Range:做分段数据请求用的。格式: Range bytes=0-1024  或者 bytes:0-1024
                    connection.setRequestProperty("Range", "bytes="+ startIndex + "-" + endIndex);
    
                    System.out.println("线程_"+threadId + "的下载起点是 " + startIndex + "  下载终点是: " + endIndex);
                    //200:请求全部资源成功, 206代表部分资源请求成功
                    if(connection.getResponseCode() == 206){
                        //获取输入流
                        InputStream inputStream = connection.getInputStream();
                        //获取前面已创建的文件.
                        RandomAccessFile randomAccessFile = new RandomAccessFile(
                                new File(targetFilePath,getFileName(url)), "rw");
                        randomAccessFile.seek(startIndex);//文件写入的开始位置.
    
    
                        /*
                         * 将网络流中的文件写入本地
                         */
                        byte[] buffer = new byte[1024];
                        int length = -1;
                        //记录本次下载文件的大小
                        int total = 0;
                        while((length = inputStream.read(buffer)) > 0){
                            randomAccessFile.write(buffer, 0, length);
                            total += length;
    
                            /*
                             * 将当前现在到的位置保存到文件中
                             */
                            downThreadStream.seek(0);
                            downThreadStream.write((startIndex + total + "").getBytes("UTF-8"));
                        }
    
                        downThreadStream.close();
                        inputStream.close();
                        randomAccessFile.close(); 
                        //删除临时文件
                        cleanTemp(downThreadFile);
                        System.out.println("线程"+ threadId + "下载完毕");
                    }else{
                        System.out.println("响应码是" +connection.getResponseCode() + ". 服务器不支持多线程下载");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
            }
        }
    
        //删除线程产生的临时文件
        private synchronized void cleanTemp(File file){
            file.delete();
        }
    
        //获取下载文件的名称
        private String getFileName(URL url){
            String filename = url.getFile();
            return filename.substring(filename.lastIndexOf("/")+1);
        }
    
           
    }
  • 相关阅读:
    Nacos启动异常:failed to req API:/api//nacos/v1/ns/instance after all servers([127.0.0.1:8848])
    多节点集群思路
    内网dns配置
    MySQL集群配置思路
    pycharm常用快捷键
    2020年11月新版CKA考试心得
    JavaScript的Map、Set、WeakMap和WeakSet
    AJAX传输二进制数据
    linux性能监测与优化的指令
    八千字硬核长文梳理Linux内核概念及学习路线
  • 原文地址:https://www.cnblogs.com/lantu1989/p/6729534.html
Copyright © 2011-2022 走看看