Sample code for the breakpoint continuation function implemented by Java
- 2020-06-12 08:57:15
- OfStack
Comments have been added to the code, so those who need them can refer to them directly. The following is the main code directly implementing the above functions:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/*
* Encode:UTF-8
*
* Author:zhiming.xu
*
* Multithreaded breakpoints download the program according to the input url And specify the number of threads to complete the breakpoint continuation function.
*
* Each thread branch is responsible for 1 Small data downloads; through RandomAccessFile Complete data integration.
*/
public class MultiTheradDownLoad {
private String filepath = null;
private String filename = null;
private String tmpfilename = null;
private int threadNum = 0;
private CountDownLatch latch = null;// Set up the 1 The code is mainly used to complete the deletion of the cache file
private long fileLength = 0l;
private long threadLength = 0l;
private long[] startPos;// Keep the starting place for each thread to download the data.
private long[] endPos;// Keep the cutoff place for each thread to download the data.
private boolean bool = false;
private URL url = null;
// With a parameter constructor, the required data is constructed first
public MultiTheradDownLoad(String filepath, int threadNum) {
this.filepath = filepath;
this.threadNum = threadNum;
startPos = new long[this.threadNum];
endPos = new long[this.threadNum];
latch = new CountDownLatch(this.threadNum);
}
/*
* A method for organizing breakpoint continuation functionality
*/
public void downloadPart() {
File file = null;
File tmpfile = null;
HttpURLConnection httpcon = null;
// In the request url The name of the obtained file resource; This does not take into account the case where the file name is empty, which might be useful UUID To generate a 1 A wei 1 To represent the file name.
filename = filepath.substring(filepath.lastIndexOf('/') + 1, filepath
.contains("?") ? filepath.lastIndexOf('?') : filepath.length());
tmpfilename = filename + "_tmp";
try {
url = new URL(filepath);
httpcon = (HttpURLConnection) url.openConnection();
setHeader(httpcon);
fileLength = httpcon.getContentLengthLong();// Gets the total length of the requested resource.
file = new File(filename);
tmpfile = new File(tmpfilename);
threadLength = fileLength / threadNum;// Size of resources to download per thread.
System.out.println("fileName: " + filename + " ," + "fileLength= "
+ fileLength + " the threadLength= " + threadLength);
if (file.exists() && file.length() == fileLength) {
System.out
.println("the file you want to download has exited!!");
return;
} else {
setBreakPoint(startPos, endPos, tmpfile);
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < threadNum; i++) {
exec.execute(new DownLoadThread(startPos[i], endPos[i],
this, i, tmpfile, latch));
}
latch.await();// When your counter is reduced to 0 Before, it would be here 1 Straight block.
exec.shutdown();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (file.length() == fileLength) {
if (tmpfile.exists()) {
System.out.println("delect the temp file!!");
tmpfile.delete();
}
}
}
/*
* Breakpoint setting method, when there is a temporary file, directly reads the breakpoint location of the last download interruption from the temporary file. There are no temporary files, i.e 1 Reset the breakpoint on the next download.
*
* rantmpfile.seek() Jump to 1 The point is to keep breakpoints as separate as possible.
*
* This is an important basis for implementing breakpoint continuation.
*/
private void setBreakPoint(long[] startPos, long[] endPos, File tmpfile) {
RandomAccessFile rantmpfile = null;
try {
if (tmpfile.exists()) {
System.out.println("the download has continued!!");
rantmpfile = new RandomAccessFile(tmpfile, "rw");
for (int i = 0; i < threadNum; i++) {
rantmpfile.seek(8 * i + 8);
startPos[i] = rantmpfile.readLong();
rantmpfile.seek(8 * (i + 1000) + 16);
endPos[i] = rantmpfile.readLong();
System.out.println("the Array content in the exit file: ");
System.out.println("thre thread" + (i + 1) + " startPos:"
+ startPos[i] + ", endPos: " + endPos[i]);
}
} else {
System.out.println("the tmpfile is not available!!");
rantmpfile = new RandomAccessFile(tmpfile, "rw");
// The last 1 The size of the cut off position of the thread is the size of the requested resource
for (int i = 0; i < threadNum; i++) {
startPos[i] = threadLength * i;
if (i == threadNum - 1) {
endPos[i] = fileLength;
} else {
endPos[i] = threadLength * (i + 1) - 1;
}
rantmpfile.seek(8 * i + 8);
rantmpfile.writeLong(startPos[i]);
rantmpfile.seek(8 * (i + 1000) + 16);
rantmpfile.writeLong(endPos[i]);
System.out.println("the Array content: ");
System.out.println("thre thread" + (i + 1) + " startPos:"
+ startPos[i] + ", endPos: " + endPos[i]);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (rantmpfile != null) {
rantmpfile.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* An internal class that implements the download function by reading breakpoints to set the interval of data requested from the server.
*/
class DownLoadThread implements Runnable {
private long startPos;
private long endPos;
private MultiTheradDownLoad task = null;
private RandomAccessFile downloadfile = null;
private int id;
private File tmpfile = null;
private RandomAccessFile rantmpfile = null;
private CountDownLatch latch = null;
public DownLoadThread(long startPos, long endPos,
MultiTheradDownLoad task, int id, File tmpfile,
CountDownLatch latch) {
this.startPos = startPos;
this.endPos = endPos;
this.task = task;
this.tmpfile = tmpfile;
try {
this.downloadfile = new RandomAccessFile(this.task.filename,
"rw");
this.rantmpfile = new RandomAccessFile(this.tmpfile, "rw");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
this.id = id;
this.latch = latch;
}
@Override
public void run() {
HttpURLConnection httpcon = null;
InputStream is = null;
int length = 0;
System.out.println("the thread " + id + " has started!!");
while (true) {
try {
httpcon = (HttpURLConnection) task.url.openConnection();
setHeader(httpcon);
// Prevent network blocking and set the specified timeout period; The unit is ms . After the specified time, an exception is thrown
httpcon.setReadTimeout(20000);// Timeout setting for reading data
httpcon.setConnectTimeout(20000);// Timeout setting for the connection
if (startPos < endPos) {
// Requesting data for a specified interval from the server is essential to implementing breakpoint continuation.
httpcon.setRequestProperty("Range", "bytes=" + startPos
+ "-" + endPos);
System.out
.println("Thread " + id
+ " the total size:---- "
+ (endPos - startPos));
downloadfile.seek(startPos);
if (httpcon.getResponseCode() != HttpURLConnection.HTTP_OK
&& httpcon.getResponseCode() != HttpURLConnection.HTTP_PARTIAL) {
this.task.bool = true;
httpcon.disconnect();
downloadfile.close();
System.out.println("the thread ---" + id
+ " has done!!");
latch.countDown();// Counter self-subtracting
break;
}
is = httpcon.getInputStream();// Gets the resource flow returned by the server
long count = 0l;
byte[] buf = new byte[1024];
while (!this.task.bool && (length = is.read(buf)) != -1) {
count += length;
downloadfile.write(buf, 0, length);
// Constantly update the starting location of each thread to download resources and write temporary files; Prepare for the breakpoint continuation
startPos += length;
rantmpfile.seek(8 * id + 8);
rantmpfile.writeLong(startPos);
}
System.out.println("the thread " + id
+ " total load count: " + count);
// Close the stream
is.close();
httpcon.disconnect();
downloadfile.close();
rantmpfile.close();
}
latch.countDown();// Counter self-subtracting
System.out.println("the thread " + id + " has done!!");
break;
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
/*
* for 1 a HttpURLConnection Simulate the request header, disguised as 1 Requests made by three browsers
*/
private void setHeader(HttpURLConnection con) {
con.setRequestProperty(
"User-Agent",
"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3");
con.setRequestProperty("Accept-Language", "en-us,en;q=0.7,zh-cn;q=0.3");
con.setRequestProperty("Accept-Encoding", "aa");
con.setRequestProperty("Accept-Charset",
"ISO-8859-1,utf-8;q=0.7,*;q=0.7");
con.setRequestProperty("Keep-Alive", "300");
con.setRequestProperty("Connection", "keep-alive");
con.setRequestProperty("If-Modified-Since",
"Fri, 02 Jan 2009 17:00:05 GMT");
con.setRequestProperty("If-None-Match", "\"1261d8-4290-df64d224\"");
con.setRequestProperty("Cache-Control", "max-age=0");
con.setRequestProperty("Referer",
"http://www.skycn.com/soft/14857.html");
}
}
Here is the test code:
public class DownLoadTest {
/**
* @param args
*/
public static void main(String[] args) {
String filepath = "http://127.0.0.1:8080/file/loadfile.mkv";
MultiTheradDownLoad load = new MultiTheradDownLoad(filepath ,4);
load.downloadPart();
}
}