/**
*
*/
package com.l000phone.multithreaddown.advanced;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Description: 多线程从服器端下载资源演示(网络出现异常,需要进行断点续传)
* Copyright (c) , 2016, Jansonxu
* This program is protected by copyright laws.
* Program Name:Download.java
* Date: 2016-2-16
*
* @author 李阳
* @version : 1.0
*/
public class AdvancedDownload {
/**
* @param args
*/
public static void main(String[] args) {
// 1、在客户端获得服务器资源的长度,根据此长度在客户端创建一个临时文件
try {
URL url = new URL(
"http://localhost:8080/ServerSide/file/VNC-5.1.1-Windows.exe");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
int resLen = conn.getContentLength();
System.out.println("要下载资源的长度是:" + resLen);
RandomAccessFile raf = new RandomAccessFile(new File(
"download/VNC-5.1.1-Windows.exe"), "rwd");// 创建临时文件
raf.setLength(resLen);
raf.close();// 关闭资源
// 2、获得每个线程下载资源的开始和结束位置
// 3、开启多个线程从服务其下载资源,直到所有的线程执行完毕
int blockSize = resLen / 3;// 每个线程平均下载的长度
AdvancedDownload outer = new AdvancedDownload();// 外部类对象
// 创建文件对象(记录各个子线程下载的最终结果)
File threadDownadStatusFile = new File(
"download/finalStauts.txt");
if (!threadDownadStatusFile.exists()) {
threadDownadStatusFile.createNewFile();
}
for (int threadId = 1; threadId <= 3; threadId++) {
// ①开始位置
int startPos = (threadId - 1) * blockSize;
// ②结束位置
int endPos = threadId * blockSize - 1;
if (threadId == 3) {
endPos = resLen - 1;
}
// ③启动子线程下载
outer.new DownloadSonThread(startPos, endPos, url,
threadId, threadDownadStatusFile).start();
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 资源下载子线程
*/
private class DownloadSonThread extends Thread {
private int startPos;
private int endPos;
private URL url;
private int threadId;
private File threadDownadStatusFile;
public DownloadSonThread(int startPos, int endPos, URL url,
int threadId, File threadDownadStatusFile) {
super();
this.startPos = startPos;
this.endPos = endPos;
this.url = url;
this.threadId = threadId;
this.threadDownadStatusFile = threadDownadStatusFile;
}
@Override
public void run() {
// ①获得连接实例
try {
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
// 读取线程字节数记录文件中的数据,作为开始线程下载的开始位置
File file = new File("download/" + threadId + ".txt");
if (file.exists()) {
BufferedReader br = new BufferedReader(new FileReader(file));
String startPosRecord = br.readLine();
startPos = Integer.parseInt(startPosRecord);
br.close();
}
// ②设置连接的属性为下载部分资源
conn.setRequestProperty("Range", "bytes=" + startPos + "-"
+ endPos);
System.out.println("来自服务器端的状态码:" + conn.getResponseCode());
// ③从服务器获取资源,填充本地客户端的临时文件
if (conn.getResponseCode() == 206) {// 206:服务器端的资源是属于分段下载的、200:服务端所有的资源都发送给了客户端
// a)获得网络字节输入流
InputStream is = conn.getInputStream();
byte[] b = new byte[1024];
int len = 0;
// b)将流中的数据写入到本地临时文件中
RandomAccessFile raf = new RandomAccessFile(new File(
"download/VNC-5.1.1-Windows.exe"), "rwd");// 向临时文件中写入数据
raf.seek(startPos);
int totalBytes = startPos;// 当前线程已经下载的字节数
while ((len = is.read(b)) != -1) {
// seek移动指针偏移量,写入数据
raf.write(b, 0, len);
totalBytes += len;// 累加目前已经下载的字节数
RandomAccessFile nowRecordLenFile = new RandomAccessFile(
new File("download/" + threadId + ".txt"),
"rwd");
nowRecordLenFile.write((totalBytes + "").getBytes());
nowRecordLenFile.close();
}
raf.close();
System.out.println("线程" + threadId + "下载资源完毕....");
FileWriter fw = new FileWriter(threadDownadStatusFile, true);
fw.write(threadId + "over");
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 读取文件中的内容,若发现内容匹配:
// 内容.contains("thread1over") 并且 内容.contains("thread2over") 并且
// 内容.contains("thread3over")
// 就删除各个临时文件
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(
threadDownadStatusFile));
String finalResultInfo = br.readLine();
if (finalResultInfo.contains("1over")
&& finalResultInfo.contains("2over")
&& finalResultInfo.contains("3over")) {
for (int threadId = 1; threadId <= 3; threadId++) {
new File("download/" + threadId + ".txt").delete();
}
br.close();
new File("download/finalStauts.txt").delete();
System.out.println("恭喜!所有临时文件都已经删除掉了哦!...");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}