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

    一、原理

    二、示例代码

    package com.shz;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.io.RandomAccessFile;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class Demo {
    
        // 定义将要开启的线程的数量
        private static int threadCount = 6;
        
        // 正在执行下载任务的线程总数
        private static int runningThreadCount = threadCount;
        
        public static void main(String[] args) throws Exception {
            String path = "http://192.168.1.101/MyWebSite/sogou.exe";
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(5000);
            conn.setRequestMethod("GET");
            int code = conn.getResponseCode();
            if (code == 200) {
                // 获取要下载的文件的大小
                int length = conn.getContentLength();
                System.out.println("文件大小:" + length);
                
                // 在客户端本地创建一个大小跟服务器文件大小一样的临时文件
                RandomAccessFile raf = new RandomAccessFile("sogou.exe", "rwd");
                raf.setLength(length);
                
                // 每个线程下载的部分文件大小(由于可能无法整除,最后一个线程下载的大小不一定为blockSize)
                int blockSize = length / threadCount;
                for (int threadId = 1; threadId <= threadCount; threadId++) {
                    int startIndex = (threadId - 1) * blockSize;
                    int endIndex = threadId * blockSize - 1;
                    if (threadId == threadCount) {
                        endIndex = length;
                    }
    
                    System.out.println("线程" + threadId + ":" + startIndex + "--->"
                            + endIndex);
                    
                    new DownloadThread(path, startIndex, endIndex, threadId).start();
                }
            } else {
                System.out.println("连接服务器失败");
            }
        }
    
        public static String getNowString()
        {
            DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return format.format(new Date());
        }
        
        private static class DownloadThread extends Thread {
            private String path;
            private int startIndex;
            private int endIndex;
            private int threadId;
    
            /**
             * 子线程下载的构造方法
             * 
             * @param path
             *            要下载的服务器文件路径
             * @param startIndex
             *            开始下载位置
             * @param endIndex
             *            结束下载位置
             * @param threadId
             *            线程Id
             */
            public DownloadThread(String path, int startIndex, int endIndex,
                    int threadId) {
                this.path = path;
                this.startIndex = startIndex;
                this.endIndex = endIndex;
                this.threadId = threadId;
            }
    
            public void run() {
                try {
                    
                    // 判断是否存在和当前线程threadId同名的文件名称“x.txt”,
                    // 如果存在,则读取文件中内容,该内容记录了上次线程已下载资源的总长度,那么当前线程开始下载的位置要加上此总长度
                    File downloadFile = new File(threadId+".txt");
                    if(downloadFile.exists() && downloadFile.length() > 0)
                    {
                        FileInputStream fis = new FileInputStream(downloadFile);
                        byte[] buffer = new byte[1024];
                        int len = fis.read(buffer);
                        String strHasDownloadLen = new String(buffer,0,len);
                        System.out.println(getNowString()+":线程"+this.threadId+"上次已下载 "+strHasDownloadLen);
                        this.startIndex += Integer.parseInt(strHasDownloadLen);
                        fis.close();
                    }
                    
                    System.out.println(getNowString()+":线程"+this.threadId+"开始下载...");                
                    URL url = new URL(this.path);
                    HttpURLConnection conn = (HttpURLConnection) url
                            .openConnection();
                    conn.setReadTimeout(5000);
                    conn.setRequestMethod("GET");
                    conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
                            + endIndex);
    
                    // 如果是请求全部资源,服务器返回200;如果是请求部分资源,服务器返回206
                    int code = conn.getResponseCode();
                    if (code == 206) {
                        InputStream is = conn.getInputStream();
                        RandomAccessFile raf = new RandomAccessFile("sogou.exe",
                                "rwd");
                        raf.seek(this.startIndex);
    
                        int len = 0;
                        int hasDownloadLen = 0;
                        byte[] buffer = new byte[1024];
                        // 把当前线程已下载的资源总长度写到文件中
                        File downloadLenFile = new File(threadId+".txt");
                        while ((len = is.read(buffer)) > 0) {
                            raf.write(buffer, 0, len);
                            
                            // 记录当前线程已下载的资源总长度
                            hasDownloadLen += len;    
                            FileOutputStream fos = new FileOutputStream(downloadLenFile);
                            fos.write(String.valueOf(hasDownloadLen).getBytes());
                            fos.close();
                        }
                        
                        is.close();
                        raf.close();
                        System.out.println(getNowString()+":线程"+this.threadId+"下载结束...");
                    } else {
                        System.out.println("线程" + this.threadId + "下载失败,服务器返回错误码:"
                                + code);
                    }
                } catch (Exception e) {
                    System.out.println("线程" + this.threadId + "下载出现异常:"
                            + e.toString());
                } finally {
                    runningThreadCount --;
                    
                    if(runningThreadCount <= 0)
                    {
                        for(int threadId=1;threadId<=threadCount;threadId++)
                        {
                            File file = new File(threadId+".txt");
                            if(file.exists())
                            {
                                file.delete();
                            }
                        }
                        
                        System.out.println(getNowString()+":文件下载结束");
                    }
                }
            }
        }
    }
    View Code
  • 相关阅读:
    MySQL5.7版本单节点大数据量迁移到PXC8.0版本集群全记录3
    19c上ADG主库sys密码修改会影响备库同步吗?
    MySQL中sql_mode的设置
    [自制工具]批量后台更新统计信息
    openssl加解密实战
    [自制工具]简便易用的ADDM报告生成工具
    MySQL5.7版本单节点大数据量迁移到PXC8.0版本集群全记录2
    MySQL5.7版本单节点大数据量迁移到PXC8.0版本集群全记录1
    Windows11如何设置经典的右键菜单
    MVC3过滤器实现多语言
  • 原文地址:https://www.cnblogs.com/shaomenghao/p/3936091.html
Copyright © 2011-2022 走看看