• Java实现断点续传+多线程下载

  如下代码所示,每一步都有注解

  思路:

    1. 通过URL连接到服务器上要下载的文件,得到文件的大小;
    2. 算出每条线程下载的开始位置和结束位置,例如,有两条线程下载100Byte的文件,则每个线程下载各下载50Byte,第一条线程下载的开始位置和结束位置为0-50Byte,第二条线程下载的开始位置和结束位置为51-100Byte;
    3. 开启多条线程下载文件,在下载之前先判断是否存在临时文件,临时文件中保存的是之前文件写入的位置(临时文件由自己生成),如果存在临时文件,则读取临时文件中的数字,将当前的开始位置换为临时文件中的数字;
    4. 在下载文件的同时,要将文件下载的位置写入到临时文件中,断点续传必须条件(上一步用到,和3对照上看);
    5. 下载完成后,将临时文件删除掉;

 

package com.test.download;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL; public class MutilDownLoad { // [1]定义下载的路径
private static String path = "http://192.168.33.10:80/test/123456.mp4"; private static final int threadCount = 3; // 假设开三个线程 private static int runningThread; // 代表当前正在运行的线程 public static void main(String[] args) { // [一]获取服务器文件的大小 要计算每个线程下载的开始位置和结束位置 try { // (1) 创建一个url对象 参数就是网址
URL url = new URL(path);
// (2)获取HttpURLConnection 链接对象
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// (3)设置参数 发送get请求
conn.setRequestMethod("GET"); // 默认请求 就是get 要大写
// (4)设置链接网络的超时时间
conn.setConnectTimeout(5000);
// (5)获取服务器返回的状态码
int code = conn.getResponseCode(); // 200 代表获取服务器资源全部成功 206请求部分资源
if (code == 200) { // (6)获取服务器文件的大小
int length = conn.getContentLength(); // [6.1]把 线程的数量赋值给正在运行的线程
runningThread = threadCount; System.out.println("length:" + length); // [二] 创建一个大小和服务器一模一样的文件 目的提前把空间申请出来
RandomAccessFile rafAccessFile = new RandomAccessFile("F:\\"
+ getFilename(path), "rw");
rafAccessFile.setLength(length); // (7)算出每个线程下载的大小
int blockSize = length / threadCount; // [三 计算每个线程下载的开始位置和结束位置 ]
for (int i = 0; i < threadCount; i++) {
int startIndex = i * blockSize; // 每个线程下载的开始位置
int endIndex = (i + 1) * blockSize - 1;
// 特殊情况 就是最后一个线程
if (i == threadCount - 1) {
// 说明是最后一个线程
endIndex = length - 1; } System.out.println("线程id:::" + i + "理论下载的位置" + ":"
+ startIndex + "-----" + endIndex); // 四 开启线程去服务器下载文件
DownLoadThread downLoadThread = new DownLoadThread(
startIndex, endIndex, i);
downLoadThread.start(); }
} } catch (Exception e) {
e.printStackTrace();
}
} // 定义线程去服务器下载文件
private static class DownLoadThread extends Thread {
// 通过构造方法把每个线程下载的开始位置和结束位置传递进来 private int startIndex;
private int endIndex;
private int threadId; public DownLoadThread(int startIndex, int endIndex, int threadId) {
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadId = threadId;
} @Override
public void run() {
// 四 实现去服务器下载文件的逻辑 try { // (1) 创建一个url对象 参数就是网址
URL url = new URL(path);
// (2)获取HttpURLConnection 链接对象
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
// (3)设置参数 发送POST请求
conn.setRequestMethod("POST"); // 默认请求 就是get 要大写
// (4)设置链接网络的超时时间
conn.setConnectTimeout(5000); // [4.0]如果中间断过 继续上次的位置 继续下载 从文件中读取上次下载的位置 File file = new File("F:\\" + getFilename(path) + threadId
+ ".txt");
if (file.exists() && file.length() > 0) {
FileInputStream fis = new FileInputStream(file);
BufferedReader bufr = new BufferedReader(
new InputStreamReader(fis));
String lastPositionn = bufr.readLine(); // 读取出来的内容就是上一次下载的位置
int lastPosition = Integer.parseInt(lastPositionn); // [4.0.1]要改变一下 startIndex 位置
startIndex = lastPosition + 1; System.out.println("线程id::" + threadId + "真实下载的位置" + ":"
+ startIndex + "-----" + endIndex); fis.close(); // 关闭流
} // [4.1]设置一个请求头Range (作用告诉服务器每个线程下载的开始位置和结束位置)
conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
+ endIndex); // (5)获取服务器返回的状态码
int code = conn.getResponseCode(); // 200 代表获取服务器资源全部成功
// 206请求部分资源 成功
if (code == 206) {
// [6]创建随机读写文件对象
RandomAccessFile raf = new RandomAccessFile("F:\\"
+ getFilename(path), "rw");
// [6]每个线程要从自己的位置开始写
raf.seek(startIndex); InputStream in = conn.getInputStream(); // [7]把数据写到文件中
int len = -1;
byte[] buffer = new byte[1024 * 1024];// 1Mb int total = 0; // 代表当前线程下载的大小 while ((len = in.read(buffer)) != -1) {
raf.write(buffer, 0, len); total += len;
// [8]实现断点续传 就是把当前线程下载的位置 给存起来 下次再下载的时候 就是按照上次下载的位置继续下载
// 就可以了
int currentThreadPosition = startIndex + total; // 比如就存到一个普通的.txt文本中 // [9]用来存当前线程下载的位置
RandomAccessFile raff = new RandomAccessFile("F:\\"
+ getFilename(path) + threadId + ".txt", "rwd");
raff.write(String.valueOf(currentThreadPosition)
.getBytes());
raff.close();
}
raf.close();// 关闭流 释放资源 System.out.println("线程id:" + threadId + "---下载完毕了"); // [10]把.txt文件删除 每个线程具体什么时候下载完毕了 我们不知道 synchronized (DownLoadThread.class) {
runningThread--;
if (runningThread == 0) {
// 说明所有的线程都执行完毕了 就把.txt文件删除
for (int i = 0; i < threadCount; i++) {
File delteFile = new File("F:\\"
+ getFilename(path) + i + ".txt");
delteFile.delete();
}
}
} } } catch (Exception e) {
e.printStackTrace();
}
}
} // 获取文件的名字
public static String getFilename(String path) { int start = path.lastIndexOf("/") + 1;
return path.substring(start);
}
}

   

  

Java多线程断点下载文件的更多相关文章

  1. java多线程断点下载原理(代码实例演示)

    原文:http://www.open-open.com/lib/view/open1423214229232.html 其实多线程断点下载原理,很简单的,那么我们就来先了解下,如何实现多线程的断点下载 ...

  2. java多线程批量下载文件

    多线程下载文件 平时开发中有时会用到文件下载,为了提高文件的下载速率,采用多线程下载能够达到事半功倍的效果: package test; /** * 文件下载类 * @author luweichen ...

  3. java 多线程断点下载功能

    import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.Rand ...

  4. java 多线程断点下载demo

    源码链接 import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java ...

  5. Java多线程断点下载

    public static class DownloadThread extends Thread{ private int threadId; private int startIndex; pri ...

  6. Android(java)学习笔记216:多线程断点下载的原理(Android实现)

    之前在Android(java)学习笔记215中,我们从JavaSE的角度去实现了多线程断点下载,下面从Android角度实现这个断点下载: 1.新建一个Android工程: (1)其中我们先实现布局 ...

  7. Android(java)学习笔记159:多线程断点下载的原理(Android实现)

    之前在Android(java)学习笔记215中,我们从JavaSE的角度去实现了多线程断点下载,下面从Android角度实现这个断点下载: 1. 新建一个Android工程: (1)其中我们先实现布 ...

  8. iOS开发网络篇—大文件的多线程断点下载

    http://www.cnblogs.com/wendingding/p/3947550.html iOS开发网络篇—多线程断点下载 说明:本文介绍多线程断点下载.项目中使用了苹果自带的类,实现了同时 ...

  9. iOS开发网络请求——大文件的多线程断点下载

    iOS开发中网络请求技术已经是移动app必备技术,而网络中文件传输就是其中重点了.网络文件传输对移动客户端而言主要分为文件的上传和下载.作为开发者从技术角度会将文件分为小文件和大文件.小文件因为文件大 ...

随机推荐

  1. bootstrap导航栏PC端移动端之不同样式

    在此之前,我先说我之所以要改变网站PC移动双端不同样式的原因. 首先我的网站用到了bootstrap响应式布局,这是我网站的PC端导航栏: 这是我网站的移动端导航栏,看着就难受: 我用谷歌浏览器F12 ...

  2. WebForm——浅拷贝与深拷贝

    注:本文整理来自连接 https://www.cnblogs.com/echolun/p/7889848.html ,感谢博主的分享 总结: 1.浅拷贝:只拷贝变量的名,而不拷贝变量的值——常为引用类 ...

  3. [转帖]三款Nehalem至强5500塔式服务器横评对决(4)

    三款Nehalem至强5500塔式服务器横评对决(4) http://tech.sina.com.cn/b/2009-12-14/05051172233_4.shtml 可以看到两路服务器的设置 基本 ...

  4. 【AtCoder】AGC011

    AGC011 A - Airport Bus 大意:有N个人,每个人只能在\([T_i,T_i +K]\)这段区间乘车,每辆车安排C人,问最少安排几辆车 直接扫,遇到一个没有车的在\(T_i +K\) ...

  5. (四)mybatis 的主键返回

    目录 文章目录 自增主键(LAST_INSERT_ID()) 非自增主键(UUID() ) 自增主键(LAST_INSERT_ID()) 在映射关系文件中配置 <!--插入用户--> &l ...

  6. 【搜索】Partition problem

    题目链接:传送门 题面: [题意] 给定2×n个人的相互竞争值,请把他们分到两个队伍里,如果是队友,那么竞争值为0,否则就为v[i][j]. [题解] 爆搜,C(28,14)*28,其实可以稍加优化, ...

  7. 把.exe的格式的运行程序加到电脑本地服务的办法(本文来源于百度)

    Instsrv.exe(可以给系统安装和删除服务) Srvany.exe(可以让程序以服务的方式运行) 方法/步骤     要实现这个功能要用到微软提供的两个小工具“instsrv.exe”和“srv ...

  8. Git 集成 Araxis Merge 作为比较和合并GUI工具的配置 参考自https://www.kancloud.cn/leviio/git/369125

    Git 集成 Araxis Merge Win10下修改git全部配置文件方法Git 集成 Araxis Merge 作为比较和合并GUI工具的配置 那global对应的 ,gitconfig文件在哪 ...

  9. iOS 定义多个参数函数的写法

    多个参数的写法 (方法的数据类型)函数名:(参数1数据类型)参数1的数值的名字 参数2的名字: (参数2数据类型) 参数2值的名字 …. ; 如  :  有三个参数 -(void)getdetailI ...

  10. JDK + Tomcat 安装 + 制作自定义镜像【第 3 篇 系统镜像】

    [第 1 篇 JDK]:https://www.cnblogs.com/del88/p/11842387.html[第 2 篇 Tomcat]:https://www.cnblogs.com/del8 ...