转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/26994463

有个朋友需要个多线程现在的例子,就帮忙实现了,在此分享下~

先说下原理,原理明白了,其实很简单:

a、对于网络上的一个资源,首先发送一个请求,从返回的Content-Length中回去需要下载文件的大小,然后根据文件大小创建一个文件。

this.fileSize = conn.getContentLength();// 根据响应获取文件大小
File dir = new File(dirStr);
this.localFile = new File(dir, filename);
RandomAccessFile raf = new RandomAccessFile(this.localFile, "rw");
raf.setLength(fileSize);
raf.close();

b、根据线程数和文件大小,为每个线程分配下载的字节区间,然后每个线程向服务器发送请求,获取这段字节区间的文件内容。

conn.setRequestProperty("Range", "bytes=" + startPos + "-"
+ endPos);// 设置获取实体数据的范围

c、利用RandomAccessFile的seek方法,多线程同时往一个文件中写入字节。

raf.seek(startPos);
while ((len = is.read(buf)) != -1)
{
raf.write(buf, 0, len);
}

分析完了原理就很简单了,我封装了一个类,利用这个类的实例进行下载,所需参数:下载资源的URI, 本地文件路径,线程的数量。

package com.zhy.mutilthread_download;

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 MultipartThreadDownloador
{ /**
* 需要下载资源的地址
*/
private String urlStr;
/**
* 下载的文件
*/
private File localFile;
/**
* 需要下载文件的存放的本地文件夹路径
*/
private String dirStr;
/**
* 存储到本地的文件名
*/
private String filename; /**
* 开启的线程数量
*/
private int threadCount;
/**
* 下载文件的大小
*/
private long fileSize; public MultipartThreadDownloador(String urlStr, String dirStr,
String filename, int threadCount)
{
this.urlStr = urlStr;
this.dirStr = dirStr;
this.filename = filename;
this.threadCount = threadCount;
} public void download() throws IOException
{
createFileByUrl(); /**
* 计算每个线程需要下载的数据长度
*/
long block = fileSize % threadCount == 0 ? fileSize / threadCount
: fileSize / threadCount + 1; for (int i = 0; i < threadCount; i++)
{
long start = i * block;
long end = start + block >= fileSize ? fileSize : start + block - 1; new DownloadThread(new URL(urlStr), localFile, start, end).start();
} } /**
* 根据资源的URL获取资源的大小,以及在本地创建文件
*/
public void createFileByUrl() throws IOException
{
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(15 * 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("Referer", urlStr);
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");
conn.connect(); if (conn.getResponseCode() == 200)
{
this.fileSize = conn.getContentLength();// 根据响应获取文件大小
if (fileSize <= 0)
throw new RuntimeException(
"the file that you download has a wrong size ... ");
File dir = new File(dirStr);
if (!dir.exists())
dir.mkdirs();
this.localFile = new File(dir, filename);
RandomAccessFile raf = new RandomAccessFile(this.localFile, "rw");
raf.setLength(fileSize);
raf.close(); System.out.println("需要下载的文件大小为 :" + this.fileSize + " , 存储位置为: "
+ dirStr + "/" + filename); } else
{
throw new RuntimeException("url that you conneted has error ...");
}
} private class DownloadThread extends Thread
{
/**
* 下载文件的URI
*/
private URL url;
/**
* 存的本地路径
*/
private File localFile;
/**
* 是否结束
*/
private boolean isFinish;
/**
* 开始的位置
*/
private Long startPos;
/**
* 结束位置
*/
private Long endPos; public DownloadThread(URL url, File savefile, Long startPos, Long endPos)
{
this.url = url;
this.localFile = savefile;
this.startPos = startPos;
this.endPos = endPos;
} @Override
public void run()
{
System.out.println(Thread.currentThread().getName() + "开始下载...");
try
{
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setConnectTimeout(15 * 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("Referer", url.toString());
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Range", "bytes=" + startPos + "-"
+ endPos);// 设置获取实体数据的范围 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");
conn.connect(); /**
* 代表服务器已经成功处理了部分GET请求
*/
if (conn.getResponseCode() == 206)
{
InputStream is = conn.getInputStream();
int len = 0;
byte[] buf = new byte[1024]; RandomAccessFile raf = new RandomAccessFile(localFile,
"rwd");
raf.seek(startPos);
while ((len = is.read(buf)) != -1)
{
raf.write(buf, 0, len);
}
raf.close();
is.close();
System.out.println(Thread.currentThread().getName()
+ "完成下载 : " + startPos + " -- " + endPos);
this.isFinish = true;
} else
{
throw new RuntimeException(
"url that you conneted has error ...");
}
} catch (IOException e)
{
e.printStackTrace();
}
} } }

createFileByUrl方法,就是我们上述的原理的步骤1,得到文件大小和创建本地文件。我在程序使用了一个内部类DownloadThread继承Thread,专门负责下载。download()方法,根据线程数量和文件大小计算每个线程需要下载的字节区间,然后开启线程去下载。

服务器端:我就扔了几个文件在Tomcat根目录做实验,下面是测试代码:

package com.zhy.mutilthread_download;

import java.io.IOException;

public class Test
{ public static void main(String[] args)
{
try
{
new MultipartThreadDownloador("http://localhost:8080/nexus.zip",
"f:/backup/nexus", "nexus.zip", 2).download();
} catch (IOException e)
{
e.printStackTrace();
} }
}

输出结果:

需要下载的文件大小为 :31143237 , 存储位置为: f:/backup/nexus/nexus.zip
Thread-1开始下载...
Thread-2开始下载...
Thread-3开始下载...
Thread-4开始下载...
Thread-4完成下载 : 23357430 -- 31143237
Thread-2完成下载 : 7785810 -- 15571619
Thread-1完成下载 : 0 -- 7785809
Thread-3完成下载 : 15571620 -- 23357429

截图:

ok,多线程下载介绍完毕,如果代码设计不合理,以及方法使用错误,欢迎各位留言,,,

源码点击下载

Java / Android 基于Http的多线程下载的实现的更多相关文章

  1. Android 基于Http的多线程下载的实现

    a.对于网络上的一个资源,首先发送一个请求,从返回的Content-Length中回去需要下载文件的大小,然后根据文件大小创建一个文件. this.fileSize = conn.getContent ...

  2. Android学习记录(6)—将java中的多线程下载移植到Android中(即多线程下载在Android中的使用)③

    在这一节中,我们就来讲多线程下载以及断点续传在android中怎么使用,前两节是为本节做准备的,没有看前两节的同学,最好看完前面的两篇文章再来看这篇.其实在android端的应用和java基本上是差不 ...

  3. 160G 视频教程(Java+Android+项目视频)免费下载

    我不喜欢多说没用,直接给下载链接,进去直接下载,下载不动的联系网站客服解决!我只和我的好朋友们分享好的视频教程 http://edu.csdn.net/main/video.shtml 视频教程目录过 ...

  4. Android开发之多线程下载、断点续传、进度条和文本显示

    代码实现了在Android环境下的多线程下载.断点续传.进度条显示和文本显示百分数: import java.io.BufferedReader; import java.io.File; impor ...

  5. Android中多线程下载列表的封装实现(含进度反馈)

    来源:http://blog.csdn.net/u011638883/article/details/17347015 实现了一下Android中的文件多线程下载模块,支持自定义线程数.断点续传.下载 ...

  6. <基于Qt与POSIX线程>多线程下载器的简易搭建

    原创博客,转载请联系博主! 本项目已托管到本人Git远程库:https://github.com/yue9944882/Snow 项目目标  Major Functionality 开发环境:  Ce ...

  7. Linux 下的多线程下载工具 Axel

    Axel 是 Linux 平台下的一款 HTTP/FTP 的高速下载工具,支持多线程以及断点续传,对于一些有速度限制的服务器上下载东西时,Axel 的速度就明显比 wget 要快一些 还有另一个基于 ...

  8. Java / Android H基于ttp多线程下载的实现

    转载请注明出处:http://blog.csdn.net/lmj623565791/article/details/26994463 有个朋友须要个多线程如今的样例,就帮忙实现了.在此分享下~ 先说下 ...

  9. 我的Android进阶之旅------>Android基于HTTP协议的多线程断点下载器的实现

    一.首先写这篇文章之前,要了解实现该Android多线程断点下载器的几个知识点 1.多线程下载的原理,如下图所示 注意:由于Android移动设备和PC机的处理器还是不能相比,所以开辟的子线程建议不要 ...

随机推荐

  1. 14.4.3.3 Making the Buffer Pool Scan Resistant

    14.4.3.3 Making the Buffer Pool Scan Resistant 让Buffer Pool 扫描 相比使用一个严格的LRU算法, InnoDB 使用一个技术来最小化数据的总 ...

  2. 如何debug ruby

    how to debug ruby: 1. 第一种方法,直接使用ruby内建的debug在命令行调试,这个个gdb或者pdb的命令差不多. ruby -r debug yourubyfile.rb 2 ...

  3. ORALCE 之LRU链与脏LRU链【转载】

    今天是2013-09-09,时别n久的一篇经典文章,有被我在google发现了,再次转载一下.学习一下. 一.LRU链: 任何缓存的大小都是有限制的,并且总不如被缓存的数据多.就像Buffer cac ...

  4. 破解phpjm.net加密,解密程序,全部公布

    原文:破解phpjm.net加密,解密程序,全部公布 2014-05-23更新: 很久没人找我解密了,看来这加密已过时,现公布我这边最新的解密工具. 若有解不出的可联系qq: 267014855 (不 ...

  5. TI推出SimpleLink低能耗蓝牙CC2541

    TI推出SimpleLink低能耗蓝牙CC2541 日前,德州仪器 (TI) 宣布推出 SimpleLink™ 低能耗蓝牙 (Bluetooth®Low Energy) CC2541-Q1, 这是一款 ...

  6. 常见问题(FAQ) | VPNCUP

    常见问题(FAQ) | VPNCUP 常见问题(FAQ) 关于FAQ 新手开始 登录验证问题 为什么刚注册后,登录VPN服务器提示错误? 免费注册的用户有哪些限制? 为什么连接免费VPN后20分钟自动 ...

  7. memwatch的使用

    博主的新Blog地址:http://www.brantchen.com 欢迎訪问:) linux下的測试工具真是少之又少,还不好用,近期试用了memwatch,感觉网上的介绍不太好,所以放在这里跟大家 ...

  8. 使用xml和java代码混合控制UI界面

    main.xml.................... <?xml version="1.0" encoding="utf-8"?> <Li ...

  9. 2014-5-22 java.lang.OutOfMemoryError: Java heap space的一次诊断

    收到消息某系统一个节点因为内存溢出而宕机.系统的中间件是weblogic.数据库的oracle. 1. 先用IBM  HeapAnalyzer分析内存溢出时的dump文件,找到占用内存最多的请求,然后 ...

  10. 【Java 它 JVM】对象的创建过程

    虚拟机会new 指令: 1.检查指令的参数可在对类的符号引用的恒定饮食定位,并检查是否已装上代表这个类的符号引用.分析和初始化.假设没有.您必须运行相应的类加载过程. 2.类加载通过审查,虚拟机将分配 ...