Java之多線程斷點下載的實現
RandomAccessFile類:
此類的實例支持對隨機訪問文件的讀取和寫入。隨機訪問文件的行為類似存儲在文件系統中的一個大型 byte 數組。存在指向該隱含數組,光標或索引,稱為文件指針;輸入操作從文件指針開始讀取字節,并隨著對字節的讀取而前移此文件指針。如果隨機訪問文件以讀取/ 寫入模式創建,則輸出操作也可用;輸出操作從文件指針開始寫入字節,并隨著對字節的寫入而前移此文件指針。寫入隱含數組的當前末尾之后的輸出操作導致該數 組擴展。該文件指針可以通過 getFilePointer 方法讀取,并通過 seek 方法設置。
下面有RandomAccessFile實現安卓下的斷點下載的demo。
服務器端可以用tomcat模擬,將被下載的測試文件放入webApp/ROOT目錄下即可。
先給出java借助HttpURLConnection類實現的多線程下載代碼:
public class MultiThread {
private static int threadCount = 3;
private static long blockSize;
private static int runningThreadCount;
public static void main(String[] args) throws Exception {
String path = "http://10.0.67.172/test.exe";
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);//超時時間
int code = conn.getResponseCode();
System.out.println(code);
if(code / 100 == 2){
int size = conn.getContentLength();//獲取資源文件的長度
System.out.println("請求資源大小:" + size);
blockSize = size / threadCount;//將資源文件分為多少塊,沒一塊的大小
runningThreadCount = threadCount;
long startIndex = 0;
long endIndex = 0;
//開啟若干個子線程去實現多線程的下載
for(int i = 0; i < threadCount; i++){
startIndex = i * blockSize;
endIndex = (i + 1) * blockSize - 1;
if(i == threadCount-1){
endIndex = size - 1;
}
System.out.println("開啟線程:" + i + ";" + "開始位置:" + startIndex + ":" + "結束位置:" + endIndex);
new DownThread(path, startIndex, endIndex, i).start();
}
}
}
private static class DownThread extends Thread{
private String path;
private long startIndex;
private long endIndex;
private int threadId;
public DownThread(String path, long startIndex, long endIndex, int threadId) {
super();
this.path = path;
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadId = threadId;
}
@Override
public void run() {
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);//設置服務器上的文件的讀取位置
int code = conn.getResponseCode();
if(code / 100 == 2){
InputStream is = conn.getInputStream();
File file = new File("temp.exe");
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.seek(startIndex);
System.out.println("第" + threadId + "個文件的開始位置:" + String.valueOf(startIndex));
int len = 0;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1){
raf.write(buffer, 0, len);//寫文件
}
raf.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}</pre>
斷點下載的原理就是將上次文件下載的位置保存為臨時文件,當完全下載完畢時再刪除。
public class MultiThread {
private static int threadCount = 3;
private static long blockSize;
private static int runningThreadCount;
public static void main(String[] args) throws Exception {
String path = "http://10.0.67.172/test.rar";
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);//超時時間
int code = conn.getResponseCode();
System.out.println(code);
if(code / 100 == 2){
int size = conn.getContentLength();//獲取資源文件的長度
System.out.println("請求資源大小:" + size);
blockSize = size / threadCount;//將資源文件分為多少塊,沒一塊的大小
runningThreadCount = threadCount;
long startIndex = 0;
long endIndex = 0;
for(int i = 0; i < threadCount; i++){
startIndex = i * blockSize;
endIndex = (i + 1) * blockSize - 1;
if(i == threadCount-1){
endIndex = size - 1;
}
System.out.println("開啟線程:" + i + ";" + "開始位置:" + startIndex + ":" + "結束位置:" + endIndex);
new DownThread(path, startIndex, endIndex, i).start();
}
}
}
private static class DownThread extends Thread{
private String path;
private long startIndex;
private long endIndex;
private int threadId;
public DownThread(String path, long startIndex, long endIndex, int threadId) {
super();
this.path = path;
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadId = threadId;
}
@Override
public void run() {
int total = 0;
try {
File positionFile = new File(threadId + ".txt");
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
//接著上次的文件繼續下載
if(positionFile.exists() && positionFile.length() > 0){
FileInputStream fis = new FileInputStream(positionFile);
BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
//獲取當前線程上次下載的總大小是多少
String lasttotalstr = reader.readLine();
int lastTotal = Integer.valueOf(lasttotalstr);
System.out.println("上次線程下載的總大小:" + lastTotal);
startIndex += lastTotal;
total += lastTotal;
fis.close();
}
conn.setReadTimeout(5000);
conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);//設置服務器上的文件的讀取位置
int code = conn.getResponseCode();
if(code / 100 == 2){
InputStream is = conn.getInputStream();
File file = new File("temp.rar");
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.seek(startIndex);
System.out.println("第" + threadId + "個文件的開始位置:" + String.valueOf(startIndex));
int len = 0;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1){
RandomAccessFile rf = new RandomAccessFile(positionFile, "rwd");
raf.write(buffer, 0, len);//寫文件
total += len;
rf.write(String.valueOf(total).getBytes());
rf.close();
}
is.close();
raf.close();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
synchronized (DownThread.class) {
System.out.println("線程" + threadId + "下載完畢了");
runningThreadCount--;
if (runningThreadCount < 1) {
System.out.println("所有的線程都工作完畢了。刪除臨時記錄的文件");
for (int i = 0; i < threadCount; i++) {
File f = new File(i + ".txt");
System.out.println(f.delete());
}
}
}
}
}
}
}</pre>
本文由用戶 mxf8 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!