您的位置:首页 > 理论基础 > 计算机网络

Java HttpUrlConnection多线程下载

2017-02-18 15:54 211 查看
以下是Java环境下HttpUrlConnection 多线程下载,其中包含临时文件,进度临时文件。

注意点:1、如果不提前获取要下载文件的大小,后面的多线程下载是无法进行的,因为不同的线程针对不同的片段下载,提前设置相同大小的临时文件,下载时就可以针对相同的片段进行替换,如果没有那样大小的临时文件,就不能进行对应的替换,比如二号进程针对200--400片段下载,需要对应着临时文件的200--400片段进行替换,所以需要应用RandomAccessFile函数,来设置文件大小。

2、对于File file = new File(文件名或者路径名);这个并不是用来创建文件的,只是创建了一个该文件的对象,硬盘上是不存在的,只有进行读写流操作才能生成。

下面是代码:

package com.wangshop.download;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class MultiDownload {

// 线程数
static int ThreadCount = 3;
static int finishedThread = 0;

// 确定下载地址
static String path = "http://192.168.1.101:8080/QQPlayer.exe";

public static void main(String[] args) {
try {
// 创建一个URL对象
URL url = new URL(path);
// 建立一个链接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 指定请求方式
conn.setRequestMethod("GET");
// 设置连接超时时间
conn.setConnectTimeout(5000);
// 设置读取超时时间
conn.setReadTimeout(5000);
// 根据服务器响应码来判断是否连接成功
if (conn.getResponseCode() == 200) {
/**
* 本次连接为了读取到文件的大小,来生成临时文件占用空间
*/
// 拿到所请求资源文件的长度
int length = conn.getContentLength();
// 创建临时文件
File file = new File("QQPlayer.exe");
// 通过RandomAccessFile类来对生成的临时文件进行访问和设置
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
// 设置临时文件的大小
raf.setLength(length);
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;
}
// 每次循环开启一个新的线程
new DownLoadThread(startIndex, endIndex, i).start();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

}

class DownLoadThread extends Thread {
int startIndex;
int endIndex;
int threadId;

public DownLoadThread(int startIndex, int endIndex, int threadId) {
super();
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadId = threadId;
}

@Override
public void run() {
try {
//根据线程ID创建进度临时文件
File progressFile = new File(threadId + ".txt");
// 判断进度临时文件是否存在
if (progressFile.exi
4000
sts()) {
// 创建一个向指定 progressFile 对象表示的文件中写入数据的文件输入流
FileInputStream fis = new FileInputStream(progressFile);
/**
* InputStreamReader 将字节流转换为字符流
* BufferedReader 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取
* 这个类就是一个包装类,它可以包装字符流,将字符流放入缓存里,先把字符读到缓存里,到缓存满了或者你flush的时候,
* 再读入内存,就是为了提供读的效率而设计的
*/
BufferedReader br = new BufferedReader(new InputStreamReader(
fis));
// 从进度临时文件中读取出上一次下载的总进度,然后与原本的开始位置相加,得到新的开始位置
//就是将字符类型数据转换为Integer整型数据
startIndex += Integer.parseInt(br.readLine());
fis.close();
}
System.out.println("线程" + threadId + "的下载区间是:" + startIndex
+ "----" + endIndex);

// 再次发送http请求,下载原文件
HttpURLConnection conn;
URL url = new URL(MultiDownload.path);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
// 设置本次http请求 所请求的数据的区间
conn.setRequestProperty("Range", "bytes=" + startIndex + "---"
+ endIndex);

// 请求部分数据,响应码是206
if (conn.getResponseCode() == 206) {
// 流里此时只有1/3源文件的数据
InputStream is = conn.getInputStream();
//字节数组
byte[] b = new byte[1024];
int len = 0;
int total = 0;
// 拿到临时文件的输入流
File file = new File("QQPlayer.exe");
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
// 把文件的写入位置移动到startIndex
raf.seek(startIndex);
while ((len = is.read(b)) != -1) {
// 每次读取流里的数据之后,同步把数据写入临时文件
raf.write(b, 0, len);
total += len;

// 生成一个专门用来记录下载进度的临时文件
RandomAccessFile progressRaf = new RandomAccessFile(progressFile,
"rwd");
// 每次读取流里数据之后,同步把当前线程下载的总进度写入临时文件中
progressRaf.write((total + "").getBytes());
progressRaf.close();
}
System.out.println("线程" + threadId
+ "下载完毕-------------------小志参上!");
raf.close();

MultiDownload.finishedThread++;
synchronized (MultiDownload.path) {
if (MultiDownload.finishedThread == MultiDownload.ThreadCount) {
for (int i = 0; i < MultiDownload.ThreadCount; i++) {
File f = new File(i + ".txt");
f.delete();
}
MultiDownload.finishedThread = 0;
}
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: