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

     文件下载原里:

      使用http协议实现多线程下载
    b.采用多线程下载,可以抢占服务器cpu的处理时间,实现快速下载
    c.使用多线程下载文件可以更快完成文件的下载,多线程下载文件之所以快,是因为其抢占的服务器资 源多。如:假设服务器同时最多服务100个用户,在服务器中一条线程对应一个用户,100条线程在计 算机中并非并发执行,而是由CPU划分时间片轮流执行,如果A应用使用了99条线程下载文件,那么相 当于占用了99个用户的资源,假设一秒内CPU分配给每条线程的平均执行时间是10ms,A应用在服务器 中一秒内就得到了990ms的执行时间,而其他应用在一秒内只有10ms的执行时间。就如同一个水龙头  
      ,每秒出水量相等的情况下,放990毫秒的水肯定比放10毫秒的水要多。
    d.多线程下载的实现过程:
      1>首先得到下载文件的长度,然后设置本地文件的长度。
      HttpURLConnection.getContentLength();
      RandomAccessFile file = new RandomAccessFile("QQWubiSetup.exe","rwd");
      file.setLength(filesize);//设置本地文件的长度
      2>根据文件长度和线程数计算每条线程下载的数据长度和下载位置。如:文件的长度为6M,线程数为 3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如上图所示。
      3>使用Http的Range头字段指定每条线程从文件的什么位置开始下载,下载到什么位置为止,如:指 定从文件的2M位置开始下载,下载到位置(4M-1byte)为止,代码如下:
      HttpURLConnection.setRequestProperty("Range", "bytes=2097152-4194303");
      4>保存文件,使用RandomAccessFile类指定每条线程从本地文件的什么位置开始写入数据。
      RandomAccessFile threadfile = new RandomAccessFile("QQWubiSetup.exe ","rwd");
      threadfile.seek(2097152);//从文件的什么位置开始写入数据
    package com.example.thread.test
    
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.RandomAccessFile;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    public class FileDownLoader {
        public static void main(String[] args) {
            try {
    
                FileDownLoader loader = new FileDownLoader();
                loader.download();
    
            } catch (Exception e) {
            }
        }
    
        public void download() throws Exception {
            String path = "http://dlsw.baidu.com/sw-search-sp/soft/3a/12350/QQ2013SP5.847223644.exe";
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5 * 1000);
            conn.setRequestMethod("GET");
            conn.setRequestProperty(
                    "Accept",
                    "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
            conn.setRequestProperty("Accept-Language", "zh-CN");
            conn.setRequestProperty("Charset", "UTF-8");
            conn.setRequestProperty(
                    "User-Agent",
                    "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");
            conn.setRequestProperty("Connection", "Keep-Alive");
            System.out.println(conn.getResponseCode());
    
            int filesize = conn.getContentLength();// 得到文件大小
            conn.disconnect();
            int threasize = 3;// 线程数
            File file = new File("1102.exe");
            DownLoaderFile downLoaderFile = new DownLoaderFile(filesize,threasize,file);
            for (int i = 0; i < threasize; i++) {
                int startpos = i * downLoaderFile.getPerThreadSize();// 计算每条线程的下载位置
                RandomAccessFile perthreadfile = new RandomAccessFile(file,"rw");
                perthreadfile.seek(startpos);// 从文件的什么位置开始写入数据
                new DownladerThread(i, path, startpos, downLoaderFile.getPerThreadSize(), perthreadfile).start();
            }
            
    
        }
        private class DownLoaderFile{
            private int perThreadSize;
            private RandomAccessFile accessFile;
            
            public DownLoaderFile(int fileLength, int threadSize, File file) {
                //将整个文件大小分成块,每个线程负责一块
                this.perThreadSize=fileLength / threadSize + 1;
                try {
                    accessFile=new RandomAccessFile(file, "rw"); 
                    //设置本地文件大小
                    accessFile.setLength(fileLength);
                    accessFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            public int getPerThreadSize() {
                return perThreadSize;
            }
        }
    
        private class DownladerThread extends Thread {
            // 从文件的什么位置开始下载
            private int startpos;
            // 每条线程需要下载的文件大小
            private int perthreadsize;
            // 下载文件的地址
            private String path;
            // 每条线程向文件对象写入的数据
            private RandomAccessFile file;
            // 线程id,提示每个线程下载信息
            private int threadid;
    
            public DownladerThread(int threadid, String path, int startpos,
                    int perthreadsize, RandomAccessFile perthreadfile) {
                this.path = path;
                this.startpos = startpos;
                this.perthreadsize = perthreadsize;
                this.file = perthreadfile;
                this.threadid = threadid;
            }
    
            @Override
            public void run() {
                InputStream inStream = null;
                try {
                    URL url = new URL(path);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    //设置Http报文头字段
                    conn.setConnectTimeout(5 * 1000);
                    conn.setRequestMethod("GET");
                    conn.setRequestProperty(
                            "Accept",
                            "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
                    conn.setRequestProperty("Accept-Language", "zh-CN");
                    conn.setRequestProperty("Charset", "UTF-8");
              //从流的什么位置开始下载 conn.setRequestProperty(
    "Range", "bytes=" + this.startpos + "-"); //获取流对象 inStream = conn.getInputStream(); byte[] buffer = new byte[1024]; int len = 0; //记录当前线程下载数据的长度,它要小于当前线程下载的文件大小 int length = 0; while (length < perthreadsize && (len = inStream.read(buffer)) != -1) { file.write(buffer, 0, len); length += len;// 累计该线程下载的总大小 System.out.println(threadid + " ... "); } //释放资源 file.close(); inStream.close(); System.out.println(threadid + "线程完成下载"); } catch (Exception e) { e.printStackTrace(); } finally { if (inStream != null) { try { inStream.close(); } catch (IOException e) { inStream = null; } } } } } }
    public class MulThreadDownLoad
    {
    public static void main(String[] args) throws Exception
    {
    String path="http://192.168.0.110:6118/HttpFileUploadTest/test.zip";
    new MulThreadDownLoad().download(path, 3);//调用下载方法,使用3个线程下载
    }
    /**
     * 下载文件的方法
     * @param path
     * @param threadsize
     * @throws Exception
     */
    private void download(String path ,int threadsize)throws Exception
    {
    URL url=new URL(path);
    HttpURLConnection conn=  (HttpURLConnection) url.openConnection();
    conn.setConnectTimeout(5000);
    conn.setRequestMethod("GET");
    if(conn.getResponseCode()==200){
    int length=conn.getContentLength();
    File file=new File(getFileName(path));//如果不给路径的话,那么默认的保存在
    //本项目的目录底下
    RandomAccessFile accessFile=new RandomAccessFile(file, "rwd");
        accessFile.setLength(length);
        accessFile.close();
    //注意:r以只读方式打开,rw:打开以便于读取和写入
       /*rws:s代表的是文件的元数据,就是指的是文件的大小了等等,当设置为rws的时
    
    候
       当文件变化的时候,会自动的把文件的内容和元数据同步到手机的设备上
       rwd:表示当文件变化的时候会自动的把文件的内容同步到手机设备上,而不是把文
    
    件的元数据也
       同步到手机设备上.
       为了避免当手机掉电的时候,会丢失数据,那么最好采用rwd,每写一些数据就立即
    
    同步到手机设备上
       不至于数据的损坏
       rw的时候,当没有这个文件的时候会创建这个文件.
       */
       int block=length%threadsize==0? length/threadsize:length/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)
    {
    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;//下载到网络文件的什么位置结束
     RandomAccessFile accessFile;
    try
    {
    accessFile = new RandomAccessFile(file, "rwd");
     accessFile.seek(start);
    HttpURLConnection conn=(HttpURLConnection) url.openConnection();
    conn.setConnectTimeout(5000);
    conn.setRequestMethod("GET");
    conn.setRequestProperty("Range", "bytes="+start+"-"+end);
    //指定下载的区域是个范围byte=0-1000
    //注意这里的conn.getResponseCode()==200应该是206,206才对,不然会报错
    //if(conn.getResponseCode()==200){
    InputStream inpuStream=conn.getInputStream();
    byte[] buffer=new byte[1024];
    int len=0;
    while((len=inpuStream.read(buffer))!=-1){
    accessFile.write(buffer,0,len);
    }
    accessFile.close();
    inpuStream.close();
    //}
    System.out.println("第"+(threadid+1)+"线程已经下载完了");
    } catch (Exception e)
    {
    e.printStackTrace();
    }
     
    }
    }
    //得到要创建的文件名,根据路径
    private String getFileName(String path)
    {
     
    return path.substring(path.lastIndexOf("/")+1);
    }
    
    }
  • 相关阅读:
    KMP算法与字符串匹配问题
    贪婪算法(贪心算法)
    普里姆算法(Prim)与最小生成树问题
    克鲁斯卡尔算法(Kruskal算法)与最小生成树问题
    Dijkstra算法与最短路径问题
    SpringCloud(十一)使用actuator和dashborad、turbine对微服务进行监控
    博客美化——页面白天黑夜切换
    Spring5学习笔记——day01
    Mybatis学习笔记——day06
    Mybatis学习笔记——day05
  • 原文地址:https://www.cnblogs.com/lbangel/p/3461361.html
Copyright © 2011-2022 走看看