关闭

JavaSE_多线程下载

标签: java多线程网络下载
222人阅读 评论(0) 收藏 举报
分类:

多线程下载

所谓多线程下载,就是将目标数据分成若干个段,每个线程负责请求、写入一段数据的下载方式,这种方式可以解决由于单线程运算速度不能发挥所有网络带宽导致的慢速,但并不会突破物理网络的最大速度。用java实现多线程下载不需要第三方框架或jar包,只是基本的网络请求和读写操作就可以完成。

用来测试的文件最好选择可执行文件,因为如果选择图片或视频等文件,即使传输过程中出现了小部分数据的错误,也难以排查。


步骤

计算每个线程需要下载多少数据,从多少开始,到多少结束,这需要请求到所有的数据,获取数据的长度,就可以根据线程的数量来分配目标数据了,得到之后就可以开启线程下载了

代码

        try {
            //发送目标文件的请求,拿到文件长度
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(8000);
            conn.setReadTimeout(8000);
            conn.setRequestMethod("GET");

            if (conn.getResponseCode() == 200) {
                //获取长度
                int length = conn.getContentLength();
                //获取文件名
                String fileName = getFileNameFromPath(path);

                //创建临时文件
                File file = new File(fileName);
                RandomAccessFile raf = new RandomAccessFile(file, "rwd");//这样文件就可以直接写到磁盘上,不经过缓冲区了。
                raf.setLength(length);//设置文件的大小

                //raf使命完成,关闭资源
                raf.close();

                //计算每个线程需要下载多少数据
                int size = length / threadCount;

                //用循环计算每个线程的下载区间,并开启线程下载
                for (int i = 0; i < threadCount; i++) {
                    int startIndex = i * size;
                    int endIndex = (i + 1) * size - 1;
                    if (i == threadCount -1){//如果是最后一个,就把剩下的全部下载完!
                        endIndex = length-1;
                    }

                    Thread thread = new MyThread(i,startIndex,endIndex);
                    thread.start();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
其中文件输出流使用RandomAccessFile的原因是能够直接将数据写入到磁盘上而不是先写入缓冲区在适当时再写入磁盘。

Java帮助文档原文:

"rws""rwd" 模式的工作方式极其类似FileChannel 类的 force(boolean) 方法,分别传递 truefalse 参数,除非它们始终应用于每个 I/O 操作,并因此通常更为高效。如果该文件位于本地存储设备上,那么当返回此类的一个方法的调用时,可以保证由该调用对此文件所做的所有更改均被写入该设备。这对确保在系统崩溃时不会丢失重要信息特别有用。如果该文件不在本地设备上,则无法提供这样的保证。


其中用for循环得到每个线程请求的目标数据信息后,开始自定义的线程对象实例,这个自定义线程对象就得到了请求数据的信息,可以在线程对象的run方法中使用了。

自定义的Thread代码

    static class MyThread extends Thread{

        private int tid, startIndex,endIndex;

        public MyThread(int tid, int startIndex, int endIndex) {
            this.tid = tid;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
        }

        @Override
        public void run() {
            try {
                URL url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setReadTimeout(8000);
                conn.setConnectTimeout(8000);
                conn.setRequestMethod("GET");
                //设置请求的数据区间
                conn.setRequestProperty("Range","bytes="+startIndex+"-"+endIndex);

                if (conn.getResponseCode() == 206){//请求部分数据成功的响应码是206
                    InputStream is = conn.getInputStream();
                    int len;
                    byte[] buf = new byte[1024];
                    File file = new File(getFileNameFromPath(path));
                    RandomAccessFile raf = new RandomAccessFile(file,"rwd");
                    raf.seek(startIndex);//设置输出流写入的开始位置

                    while ((len = is.read(buf))!=-1){
                        raf.write(buf,0,len);
                    }
                    is.close();
                    raf.close();
                    System.out.println("第"+tid+"下载完毕");
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
其中需要注意 Http请求部分部分数据成功得到的响应式206,并不是200。
其中必须要在连接中声明要请求的数据的区间,也要声明输出流写入文件的位置。

0
0
查看评论

多线程下载的原理

假如我们把一个服务器上的文件看作是一个水缸里的水的话,那么多线程下载就相当于从水缸上打了多个小孔,然后塞进去小管道进行抽水。呵呵,也许这个比喻不够准确。多线程下载大致可分为以下几个步骤: 一、首先在本地创建一个与服务器文件大小相同的临时文件(这个很好理解,如果我想下个2G的电影,我得给先在本地占用...
  • howlaa
  • howlaa
  • 2014-03-23 17:42
  • 9189

5、HttpClient、多线程下载、HttpUtils

HttpClient发送get请求 创建一个客户端对象HttpClient client = new DefaultHttpClient(); 创建一个get请求对象HttpGet hg = new HttpGet(path); 发送get请求,建立连接,返回响应头对象HttpResponse hr...
  • guanhang89
  • guanhang89
  • 2016-05-08 17:56
  • 1195

linux 多线程下载工具axel

Linux下用的最多的下载工具莫过于wget和curl,这两个工具虽然堪称经典。但其单线程的速度越来越不能大软件的下载。 Axel是Linux的一个下载工具。他可以进行多线程下载、断点续传和限速下载。安装和操作非常简单。 1  下载axel插件的rpm包 ...
  • B_H_L
  • B_H_L
  • 2015-03-24 10:54
  • 3490

在Http协议下实现多线程断点的下载

0.使用多线程下载会提升文件下载的速度,那么多线程下载文件的过程是: (1)首先获得下载文件的长度,然后设置本地文件的长度     HttpURLConnection.getContentLength();     RandomAcc...
  • yinbucheng
  • yinbucheng
  • 2016-07-11 20:41
  • 885

Http的多线程下载的实现

a、对于网络上的一个资源,首先发送一个请求,从返回的Content-Length中回去需要下载文件的大小,然后根据文件大小创建一个文件。 b、根据线程数和文件大小,为每个线程分配下载的字节区间,然后每个线程向服务器发送请求,获取这段字节区间的文件内容。 c、利用RandomAccessFile的...
  • honlangwu
  • honlangwu
  • 2016-09-14 16:39
  • 1517

多线程下载原理及核心代码

假如我们把一个服务器上的文件看作是一个水缸里的水的话,那么多线程下载就相当于从水缸上打了多个小孔,然后塞进去小管道进行抽水。呵呵,也许这个比喻不够准确。多线程下载大致可分为以下几个步骤: 一、首先在本地创建一个与服务器文件大小相同的临时文件(这个很好理解,如果我想下个2G的电影,我得给先在本地占用2...
  • y_chengyong
  • y_chengyong
  • 2015-03-04 11:41
  • 589

让APACHE防止多线程下载

让APACHE防止多线程下载 http://www.lelew.com/  2004-05-10 13:05:14 下面是sane@nsfocus.com写的一些关于mod_limitipconn.c的文档,可以参考一下: [作者: sane@nsfocus.com ] mod_...
  • bjbs_270
  • bjbs_270
  • 2004-10-11 09:35
  • 1320

多线程下载及XUtils框架使用

一、多线程下载
  • duncan891101
  • duncan891101
  • 2014-06-27 12:13
  • 1337

Java--多线程下载

package com.jwzhangjie; /** * 说明: * 每一个线程下载的位置计算方式: * 开始位置: * (线程id - 1)*每一块大小 * 结束位置: * (线程id*每一块大小) - 1 * ---注意有时候不一定能够整除,所以最后一个线...
  • jwzhangjie
  • jwzhangjie
  • 2013-08-04 20:37
  • 8541

Java多线程下载,断点续传

转载请标明出处:http://blog.csdn.net/wu_wxc/article/details/53706114 本文出自【吴孝城的CSDN博客】 在Java中实现断点续传和多线程下载package cn.wuxiaocheng; import java.io.BufferedRead...
  • wu_wxc
  • wu_wxc
  • 2016-12-17 11:58
  • 484
    个人资料
    • 访问:16595次
    • 积分:605
    • 等级:
    • 排名:千里之外
    • 原创:45篇
    • 转载:3篇
    • 译文:0篇
    • 评论:1条