多线程下载断点续传
来源:互联网 发布:php面向对象的封装 编辑:程序博客网 时间:2024/06/07 17:23
多线程下载断点续传
多线程下载断点续传
1.了解一下多线程下载的思路
思路:开启多个线程下载同一个文件,这样可以使我们的下载文件的速度加快。如果我们使用单一的线程去下载。下载速度慢。
断点续传
1.断点续传需要在下载过程中记录每条线程的下载进度2.每次下载开始之前先读取数据库,查询是否有未完成的记录,有就继续下载,没有则创建新记录插入数据库3.在每次向文件中写入数据之后,在数据库中更新下载进度4.下载完成之后删除数据库中下载记录
多线程下载的步骤
(1)首先获得下载文件的长度,然后设置本地文件的长度。
HttpURLConnection.getContentLength();//获取下载文件的长度
RandomAccessFile file = new RandomAccessFile(“QQWubiSetup.exe”,”rwd”);
file.setLength(filesize);//设置本地文件的长度
(2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。
如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如
例如10M大小,使用3个线程来下载,
线程下载的数据长度 (10%3 == 0 ? 10/3:10/3+1) ,第1,2个线程下载长度是4M,第三个线程下载长度为2M
下载开始位置:线程id*每条线程下载的数据长度 = ?
下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?
(3)使用Http的Range头字段指定每条线程从文件的什么位置开始下载,下载到什么位置为止,
如:指定从文件的2M位置开始下载,下载到位置(4M-1byte)为止
代码如下:HttpURLConnection.setRequestProperty(“Range”, “bytes=2097152-4194303”);
(4)保存文件,使用RandomAccessFile类指定每条线程从本地文件的什么位置开始写入数据。
RandomAccessFile threadfile = new RandomAccessFile(“QQWubiSetup.exe “,”rwd”);
threadfile.seek(2097152);//从文件的什么位置开始写入数据
多线程下载断点续传的源码:
/** * 开启线程的数量 */ static int threadCount=3; /** * 访问下载的路径 */ static String path="http://169.254.87.122:8080/baofeng.exe"; static int threadFinished=0; public static void main(String[] args) { try { //创建URL对象 参数:设置路径 URL url=new URL(path); //打开连接,通过强制类型转换HttpURLConnection HttpURLConnection connection=(HttpURLConnection) url.openConnection(); //设置请求的方式 connection.setRequestMethod("GET"); //设置读取的时间 connection.setReadTimeout(5000); //设置连接的时间 connection.setConnectTimeout(5000); if (connection.getResponseCode()==200) { //拿到要下载文件的大小 int length = connection.getContentLength(); //指定临时文件的路径和文件名 File file=new File(getFileName(path)); //创建随机存储文件对象 RandomAccessFile raf=new RandomAccessFile(file, "rwd"); //设置临时文件的大小和服务器的一模一样 raf.setLength(length); //计算每个线程下载的字节数 int size=length/threadCount; for (int i = 0; i <threadCount; i++) { //计算3个线程的开始位置和结束位置 int startIndex=i*size; int endIndex=(i+1)*size-1; //如果是最后一个线程,那么结束位置特殊处理 if (i==threadCount-1) { endIndex=length-1; } System.out.println("线程"+i+"-----------"+startIndex+"-------"+endIndex); DowndLoadThread thread = new DowndLoadThread(i, startIndex, endIndex); thread.start(); } } } catch (Exception e) { e.printStackTrace(); } } /** * 得到文件名字的 * @param path 传入的访问的路径 * @return 返回处理后的结果 */ public static String getFileName(String path){ //找到最后/的索引 int index = path.lastIndexOf("/"); //进行截取 return path.substring(index+1); } static class DowndLoadThread extends Thread{ int threadId; int startIndex; int endIndex; /** * 创建有参构造函数 * @param threadId 第几个线程的 * @param startIndex 开始的索引 * @param endIndex 结束的索引 */ public DowndLoadThread( int threadId,int startIndex, int endIndex) { super(); this.startIndex = startIndex; this.endIndex = endIndex; this.threadId = threadId; } @Override public void run() { super.run(); URL url; try { //设置线程从那个位置开始写入数据到临时文件 File fileProgress=new File("h://"+threadId+".txt"); //判断下载的临时文件是否存在 if (fileProgress.exists()) { FileInputStream fis=new FileInputStream(fileProgress); BufferedReader br=new BufferedReader(new InputStreamReader(fis)); //拿到临时文件所存储的位置 int newStartIndex = Integer.parseInt(br.readLine()); startIndex=newStartIndex; System.out.println("线程"+threadId+"最终位置---------------"+startIndex); } url = new URL(path); HttpURLConnection connection=(HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setReadTimeout(5000); connection.setConnectTimeout(5000); //设置请求数据的范围 connection.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex); if (connection.getResponseCode()==206) { InputStream is = connection.getInputStream(); int len=0; byte[] b=new byte[1024]; int total=0; File file=new File("h://"+MuiltDownLoad.getFileName(path)); //创建随机文件的存储对象 RandomAccessFile raf=new RandomAccessFile(file, "rwd"); raf.seek(startIndex); //记录当前下载进度 int currentPosition=startIndex; while((len=is.read(b))!=-1){ //把下载下来的临时文件写入raf临时文件 raf.write(b, 0, len); total+=len; @SuppressWarnings("resource") RandomAccessFile rafProgress=new RandomAccessFile(fileProgress, "rwd"); currentPosition=startIndex+total; //把下载进度写入rafProgress临时文件,下一次下载时作为新的startIndex rafProgress.write((currentPosition+"").getBytes()); System.out.println("线程"+threadId+"---------------"+total); } raf.close(); System.out.println("线程"+threadId+"下载完毕"); MuiltDownLoad.threadFinished++; //如果这个条件成立,说明线程下载完毕 synchronized (MuiltDownLoad.path) { if (MuiltDownLoad.threadFinished==MuiltDownLoad.threadCount) { for (int i = 0; i < MuiltDownLoad.threadCount; i++) { File temp=new File("h://"+i+".txt"); temp.delete(); } MuiltDownLoad.threadFinished=0; } } } } catch (Exception e) { e.printStackTrace(); } } }
- 多线程断点续传后台下载
- 多线程断点续传后台下载
- android 多线程断点续传下载
- 多线程断点续传后台下载
- 多线程并行下载,断点续传
- Android多线程.断点续传下载
- android 多线程断点续传下载
- Android 多线程下载断点续传
- Java多线程断点续传下载
- 多线程断点续传后台下载
- Android多线程断点续传下载
- 多线程断点续传下载Demo
- 多线程下载 断点续传
- 多线程断点续传下载
- 多线程断点续传下载。
- Android多线程断点续传下载
- JAVA多线程断点续传下载
- android多线程断点续传下载
- shell知识点整理
- BitmapDemo
- Java 数据结构之有序数组,二分查找法
- H-Index II
- LUA———Lua和C 区别
- 多线程下载断点续传
- DHTML技术:表单验证<form>
- 图的基本算法
- 【干货】Android应用架构笔记
- 初学ML笔记N0.1——线性回归,分类与逻辑斯蒂回归,通用线性模型
- SIP Call Flow - Registration
- Docker 从零开始制作基础镜像[centos]
- [综合面试] 牛人整理分享的面试知识:操作系统、计算机网络、设计模式、Linux编程,数据结构总结
- CXF服务器发布,客户端调用