多线程下载在Android开发中经常用到,多下线程下载,其实就是将一个下载任务分布下载,使得下载的速度更快,用户体验更好。
原理很简单:
下面我们就来实现以下多线程下载吧;如图
根据下载的文件大小开启合理的线程,是一种良好的编码习惯,有时候线程开多了,占用cpu资源浪费,所以,更具需求来来开启线程大小,是一种合理的编码;代码如下:
package mlitdowloadfile;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
public class Test {
static HttpURLConnection open;
static int threadcontext=3;//线程大小
static String urls="http://localhost:8080/test.zip";
static int threadfinsh=0;//记录文件是否全部下载完成
public static void main(String[] args) {
try {
URL url=new URL(urls);
open=(HttpURLConnection) url.openConnection();
open.setReadTimeout(30000);
open.setConnectTimeout(30000);
open.setRequestMethod("GET");
if (open.getResponseCode()==200) {
System.out.println("请求成功");
int length=open.getContentLength();//获得文件大小
File file=new File(getFileName(urls));
//创建临时文件,与服务器大小一样
RandomAccessFile randomAccessFile=new RandomAccessFile(file, "rwd");
randomAccessFile.setLength(length);
//计算每个线程下载的大小
int size=length/threadcontext;
for (int i = 0; i < threadcontext; i++) {
int startindex=i*size;//开始下载位置
int endindex=(i+1)*size-1;//结束下载位置
if (i==threadcontext-1) {
endindex=length-1;
}
System.out.println("线程"+i+"的开始结束位置"+startindex+"--"+endindex);
//开启多线程
new downLooad(i, startindex, endindex).start();
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String getFileName(String path){
int index=path.indexOf(".");
return path.substring(index+1);
}
}
class downLooad extends Thread{
int threadid;
int startindex;
int endindex;
public downLooad(int threadid,int startindex,int endindex){
this.endindex=endindex;
this.startindex=startindex;
this.threadid=threadid;
}
@Override
public void run() {
try {
File temp=new File(threadid+".txt");
if (temp.exists()) {
FileInputStream fileInputStream =new FileInputStream(temp);
InputStreamReader inputStreamReader=new InputStreamReader(fileInputStream);
BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
String string=bufferedReader.readLine();
startindex=Integer.parseInt(string);
System.out.println("下载位置"+string);
fileInputStream.close();
}
URL url=new URL(Test.urls);
HttpURLConnection open=(HttpURLConnection) url.openConnection();
open.setReadTimeout(30000);
open.setConnectTimeout(30000);
open.setRequestMethod("GET");
//设置多线程请求数据范围
open.setRequestProperty("Range", "bytes="+startindex+"-"+endindex);
//请求部分数据且成功的状态码
if (open.getResponseCode()==206) {
File file=new File(Test.getFileName(Test.urls));
//创建临时文件,与服务器大小一样
RandomAccessFile randomAccessFile=new RandomAccessFile(file, "rwd");
randomAccessFile.seek(startindex);//写入位置进行位移
InputStream inputStream=open.getInputStream();
int len=0;
int lening=0;
byte[] buffer=new byte[4096];
while ((len=inputStream.read(buffer))!=-1) {
randomAccessFile.write(buffer, 0, len);
lening+=len;
//添加断点续传
RandomAccessFile rAccessFile=new RandomAccessFile(temp, "rwd");
rAccessFile.write((startindex+lening+"").getBytes("utf-8"));
rAccessFile.close();
System.out.println("线程"+threadid+"已经下载"+lening);
}
randomAccessFile.close();
System.out.println("线程"+threadid+"下载完毕");
Test.threadfinsh++;
//线程安全(同步语句块)
synchronized (url) {
if (Test.threadfinsh==Test.threadcontext) {
for (int i = 0; i <Test.threadfinsh; i++) {
File tempFile=new File(i+".txt");
tempFile.delete();
}
Test.threadfinsh=0;
}
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}