服务器上有10个字节的数据,如果目前我们有三条线程从服务器上取数据,他们分别是:
线程0、1、2,
2)那么我们每条线程负责下载的数据量是多少呢?
根据公式计算计算,每条线程负责下载的数据量是:10/3+1 = 3+1 =4;
0、1线程负责下载的数据量分别是4,2线程负责下载的数据量是2,因为下载道10的长度的时候就停止了;
3)开启多线程分别从网络文件的不同位置下载该文件,并从本地文件的相同位置写入数据,要计算出每条线程从网络文件的什么位置开始下载数据,到什么位置结束。
每条线程开始下载的位置是:
每条线程下载结束的位置是:
int end = (threadId+1)*block—1
import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
public class BreakPointDownload {
/**
* @param args
* @throws MalformedURLException
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
String path = "";
new BreakPointDownload().download(path, 3);
}
/**
* use:下载文件
*
* @param path
* @param i
* @throws Exception
*/
private void download(String path, int threadSize) throws Exception {
// TODO Auto-generated method stub
URL url = new URL(path);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
if (conn.getResponseCode() == 200) {
int contentLength = conn.getContentLength();// 获取文件的长度
File file = new File(getFileName(path));
RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");// 在本地生成一个和网络上文件长度相等的文件
accessFile.setLength(contentLength);
accessFile.close();
// 计算每条线程负责下载的数据量
int block = contentLength % threadSize == 0 ? contentLength
/ threadSize : contentLength / threadSize + 1;
for (int threadId = 0; threadId < threadSize; threadId++) {
new DownloadThread(threadId, block, url, file).start();
}
} else {
System.out.println("文件下载失败!");
}
}
private class DownloadThread extends Thread {
private int threadId;
private int block;
private URL url;
private File file;
public DownloadThread(int threadId, int block, URL url, File file) {
// TODO Auto-generated constructor stub
this.threadId = threadId;
this.block = block;
this.url = url;
this.file = file;
}
@Override
public void run() {
int start = threadId * block;// 计算该线程从网络文件的什么位置开始下载
int end = (threadId + 1) * block - 1;// 该线程下载结束的位置
try {
//单条线程下载数据
RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");// 在本地生成一个和网络上文件长度相等的文件
accessFile.seek(start);
// 请求网络文件的某一个区域的数据
HttpsURLConnection conn = (HttpsURLConnection) url
.openConnection();
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
if (conn.getResponseCode() == 206) {//注意:在多线程下载的时候判断码不是200 而是 206
InputStream in = conn.getInputStream();
byte[] buffer = new byte[1024];
int lenght = 0;
while( (lenght = in.read(buffer)) != -1){
accessFile.write(buffer, 0, lenght);
}
accessFile.close();
in.close();
}
System.out.println("第"+threadId+"条下载完毕!");
} catch (Exception e) {
e.printStackTrace();
}
super.run();
}
}
private String getFileName(String path) {
return path.substring(path.lastIndexOf("/") + 1);
}
}
线程0、1、2,
2)那么我们每条线程负责下载的数据量是多少呢?
每条线程下载的数据量是:
int block = 文件长度%N == 0 ?文件长度/N : 文件长度/N+1;
eg:
那么着10个字节的数据用三条线程来下载,每条线程负责下载的数据量为:
int block = 10%3 == 0? 10/3 :10/3+1;根据公式计算计算,每条线程负责下载的数据量是:10/3+1 = 3+1 =4;
0、1线程负责下载的数据量分别是4,2线程负责下载的数据量是2,因为下载道10的长度的时候就停止了;
3)开启多线程分别从网络文件的不同位置下载该文件,并从本地文件的相同位置写入数据,要计算出每条线程从网络文件的什么位置开始下载数据,到什么位置结束。
每条线程开始下载的位置是:
int start = threadId * block
eg:那么第一条线程id=0,那么开始下载的位置便是:0*4 = 0;第二条线程的id=1,则其开始下载的位置是1*4 = 4;第三条线程开始下载的位置为:2*4 = 8;
每条线程下载结束的位置是:
int end = (threadId+1)*block—1
那么结束的位置分别为:3,7,10,因为最后一条线程下载到10的时候,没有资源下载便会停止。
多线程下载的核心代码如下:
import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
public class BreakPointDownload {
/**
* @param args
* @throws MalformedURLException
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
String path = "";
new BreakPointDownload().download(path, 3);
}
/**
* use:下载文件
*
* @param path
* @param i
* @throws Exception
*/
private void download(String path, int threadSize) throws Exception {
// TODO Auto-generated method stub
URL url = new URL(path);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
if (conn.getResponseCode() == 200) {
int contentLength = conn.getContentLength();// 获取文件的长度
File file = new File(getFileName(path));
RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");// 在本地生成一个和网络上文件长度相等的文件
accessFile.setLength(contentLength);
accessFile.close();
// 计算每条线程负责下载的数据量
int block = contentLength % threadSize == 0 ? contentLength
/ threadSize : contentLength / threadSize + 1;
for (int threadId = 0; threadId < threadSize; threadId++) {
new DownloadThread(threadId, block, url, file).start();
}
} else {
System.out.println("文件下载失败!");
}
}
private class DownloadThread extends Thread {
private int threadId;
private int block;
private URL url;
private File file;
public DownloadThread(int threadId, int block, URL url, File file) {
// TODO Auto-generated constructor stub
this.threadId = threadId;
this.block = block;
this.url = url;
this.file = file;
}
@Override
public void run() {
int start = threadId * block;// 计算该线程从网络文件的什么位置开始下载
int end = (threadId + 1) * block - 1;// 该线程下载结束的位置
try {
//单条线程下载数据
RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");// 在本地生成一个和网络上文件长度相等的文件
accessFile.seek(start);
// 请求网络文件的某一个区域的数据
HttpsURLConnection conn = (HttpsURLConnection) url
.openConnection();
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
if (conn.getResponseCode() == 206) {//注意:在多线程下载的时候判断码不是200 而是 206
InputStream in = conn.getInputStream();
byte[] buffer = new byte[1024];
int lenght = 0;
while( (lenght = in.read(buffer)) != -1){
accessFile.write(buffer, 0, lenght);
}
accessFile.close();
in.close();
}
System.out.println("第"+threadId+"条下载完毕!");
} catch (Exception e) {
e.printStackTrace();
}
super.run();
}
}
private String getFileName(String path) {
return path.substring(path.lastIndexOf("/") + 1);
}
}