import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.net.HttpURLConnection;
public class DownUtil {
private String mPath; // 就是整个的URL地址
private String mTargetFileName;// 文件名
private int mThreadNum; // 线程数目
private DownThread[] mThreads; // 自己的下载线程数组
private int mFileSize;
public DownUtil(String path, String targetFile, int threadNum) {
mPath = path;
mTargetFileName = targetFile;
mThreadNum = threadNum;
mThreads = new DownThread[mThreadNum]; // 这里只是new了一个引用的数组
}
/**
* 下载函数 注意一个概念,URL类是远程服务器上资源的描述符,URLConnection是app和远程资源的连接
*
* @throws IOException
* */
public void download() throws IOException {
// 1 创建URL对象
URL url = new URL(mPath);
// A 调用URL对象的openConnection()创建URLConnection对象
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// B 设置URLConnection的参数和普通请求属性
conn.setConnectTimeout(5 * 100);
// C 设置请求头字段 方法很多setAllowUserInterface(),setDoInput(),setDoOutput()
conn.setRequestMethod("GET");
conn.setRequestProperty(
"Accept",
"image/gif, image/x-xbitmap, image/jpeg, image/pjpeg,"
+ " application/vnd.ms-excel, application/vnd.ms-powerpoint,"
+ " application/msword, application/x-silverlight, "
+ "application/x-shockwave-flash, */* "); // 客户端可识别的内容类型列表
conn.setRequestProperty("Accept-Language", "zh-CN");
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Connection", "Keep-Alive");
// D 发送GET请求则调用connect建立和远程资源的连接;发送POST请求则获取URLConnection对象的输出流
// E 访问远程资源的头字段或者通过输入流读取远程资源的数据
// 2 获取指定URL对象所指向资源的大小
mFileSize = conn.getContentLength(); // 这里做这么多事只是为了取得这个资源大小而已
conn.disconnect();
// 3 本地磁盘上创建一个与网络资源同样大小的空文件
RandomAccessFile targetFile = new RandomAccessFile(mTargetFileName,
"rw");
targetFile.setLength(mFileSize);
targetFile.close();
// 4 分配各线程下载文件的各个部分
int currentPartSize = mFileSize / mThreadNum + 1;
// 5 依次创建,启动线程进行下载
for (int i = 0; i < mThreadNum; ++i) {
// 计算每一个线程下载的开始位置
int startPos = i * currentPartSize;
// 每个线程使用一个RandomAccessFile对象进行下载
RandomAccessFile currentPart = new RandomAccessFile(
mTargetFileName, "rw");
// 定位这个线程的下载位置
currentPart.seek(startPos);
// 创建并启动线程
mThreads[i] = new DownThread(startPos, currentPartSize, currentPart);
mThreads[i].start();
}
}
/**
* 实现对下载进度的查询
* */
public double getCompleteRate() {
int sumSize = 0;
for (int i = 0; i < mThreadNum; ++i) {
sumSize += mThreads[i].getLength(); // length变量表示线程当前已经下载的量
}
return sumSize * 1.0 / mFileSize;
}
/**
* 下载子线程
* */
private class DownThread extends Thread {
// 下载起始位置
private int mStartPos;
// 负责的文件大小
private int mCurrentPartSize;
// 当前线程需要下载的文件块
private RandomAccessFile mCurrentPart;
private volatile int mLength;
public DownThread(int startPos, int currentPartSize,
RandomAccessFile currentPart) {
mStartPos = startPos;
mCurrentPart = currentPart;
mCurrentPartSize = currentPartSize;
}
public int getLength() {
return mLength;
}
public void run() {
// 下载的过程就是从url的输入流中把数据取出来存到文件中去
try {
URL url = new URL(mPath);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setConnectTimeout(500);
conn.setRequestMethod("GET"); // 起始行 中包括method 和url以及http版本
conn.setRequestProperty(
"Accept",
"image/gif, image/x-xbitmap, image/jpeg, image/pjpeg,"
+ " application/vnd.ms-excel, application/vnd.ms-powerpoint,"
+ " application/msword, application/x-silverlight, "
+ "application/x-shockwave-flash, */* "); // 客户端可识别的内容类型列表
conn.setRequestProperty("Accept-Language", "zh-CN");
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Connection", "Keep-Alive");
InputStream inStream = conn.getInputStream();
inStream.skip(mStartPos);
byte[] buffer = new byte[1024];
int hasRead = 0;
while(mLength < mCurrentPartSize
&& (hasRead = inStream.read(buffer)) > 0) { // 没下完,同时每次都下到了数据,用自己的raf写入
mCurrentPart.write(buffer,0,hasRead);
mLength += hasRead;
}
// 这里表示该线程负责部分下完,释放资源
mCurrentPart.close();
inStream.close(); // 关闭url对象的输入流
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
转载于:https://my.oschina.net/u/1024767/blog/476233