多线程下载,最简单也是最直接的可以使用别人已经写好的框架,就不必重复造轮子了,可以参考github上的 xutils3 框架,支持文件上传下载等诸多功能,https://github.com/wyouflf/xUtils3
下面记录一下自己使用randomaccessfile来实现下载功能的代码:
1.在本地创建同将要下载的文件同大小的文件
int fileLength= con.getContentLength();
//拿到操作文件的对象:
RandomAccessFile ras= createRandomAccessFile(getFileName(path), fileLength);
// ras.close();
2.开启多个线程,并分配每个线程下载的文件大小
//启动三个线程去下载文件,同时要计算好每个线程下载的文件的起始位置
int blockSize=fileLength/threadCount;
for(int threadId=0;threadId<threadCount;threadId++){
int startIndex=threadId*blockSize;
int endIndex=(threadId+1)*blockSize-1;
if(threadId==(threadCount-1)){
endIndex=fileLength-1;
}
new DownloadFilePartThread(threadId,startIndex,endIndex)
.start();
}
3.循环的将读取到的数据写入到文件对应的位置中
int length=conn.getContentLength();
//获取服务器返回的数据,然后将返回的数据存入这个文件中
RandomAccessFile raf =createRandomAccessFile(getFileName(path), length);
InputStream in = conn.getInputStream();
//读取数据
int len=0;
byte[] buffer=new byte[1024];
while((len=in.read(buffer))>0){
raf.write(buffer, 0, len);
}
为了避免在下载的时候服务器断掉致使下载内容要重新下载,可以边下载边记录以及下载到的位置并将其写入到某个文件中,然后下载的时候读取,并判断已经下载到的位置并设置起始下载的地方
<span style="font-size:14px;">currentPosition=currentPosition+len;
// File info = new File(threadId + ".position");
// RandomAccessFile rf = new RandomAccessFile(info, "rwd");
RandomAccessFile rf =createRandomAccessFile(threadId + ".position",5);
rf.write(String.valueOf(currentPosition).getBytes());
rf.close();</span>
最后上整个下载的源码,虽然比较的简单但是也五脏俱全嘛
public class MainActivity extends ActionBarActivity {
//规定服务器线程下载的数量
private static int threadCount=3;
// //记录正在进行下载的线程的数量
// private static int runningThreadCount=3;
//请求的服务器的地址:
private static String path="http://192.168.110.102:8080/file.txt";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建请求服务器的线程
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
URL url=new URL(path);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
//设置请求的属性:
con.setRequestMethod("GET");
con.setReadTimeout(5000);
int code=con.getResponseCode();
//200:请求状态正常
if(code==200){
int fileLength= con.getContentLength();
//拿到操作文件的对象:
RandomAccessFile ras= createRandomAccessFile(getFileName(path), fileLength);
// ras.close();
//启动三个线程去下载文件,同时要计算好每个线程下载的文件的起始位置
int blockSize=fileLength/threadCount;
for(int threadId=0;threadId<threadCount;threadId++){
int startIndex=threadId*blockSize;
int endIndex=(threadId+1)*blockSize-1;
if(threadId==(threadCount-1)){
endIndex=fileLength-1;
}
new DownloadFilePartThread(threadId,startIndex,endIndex)
.start();
}
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
/**
* 如果手机有root了,可以直接这样写
* File file = new File(getFileName(path));
RandomAccessFile raf = new RandomAccessFile(file, "rw");
raf.setLength(length);
raf.close();
* @param fileName
* @param length
* @return
*/
public RandomAccessFile createRandomAccessFile(String fileName,int length){
String filePath = this.getFilesDir().getPath().toString() + "/"+fileName;
System.out.println(filePath);
File file=new File(filePath);
RandomAccessFile ras=null;
try {
ras = new RandomAccessFile(file, "rw");
ras.setLength(length);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ras;
}
/**
* 根据路径返回文件的名称:
* @param path
* @return
*/
public static String getFileName(String path){
int index=path.lastIndexOf("/");
return path.substring(index+1);
}
class DownloadFilePartThread extends Thread{
//线程的ID号
private int threadId;
//线程的起始位置
private int startIndex;
//线程的结束位置
private int endIndex;
//线程当前下载到的位置
private int currentPosition;
public DownloadFilePartThread(int threadId, int startIndex, int endIndex) {
super();
this.threadId = threadId;
this.startIndex = startIndex;
this.endIndex = endIndex;
currentPosition = startIndex;
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("第 " + threadId + "线程开始 下载了 : 下载 从 "
+ startIndex + "~ " + endIndex);
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
// 在多线 程 下载的时候 , 每条线程 只需要 目标 文件的 一部分的数据
// 需要 告诉 服务器, 只需要 那一段的数据
// 通过 设置 http的 请求头 可以去实现 , 告诉 服务器, 只需要目标 段的数据
//告诉服务器下载的起始位置: startIndex ---- endIndex
// conn.setRequestProperty("range", "bytes=" + startIndex + "-"
// + endIndex);
//创建写currentPosition的文件来判断文件是否被下载过
int alreadyWritePosition=0;
File f=new File(threadId+".postion");
if(f.exists()&&f.length()>0){
//表示曾经下载过,则读取这个已经下载到的位置,然后继续下载
alreadyWritePosition= getPositionInFile(f);
// 告诉 服务器要数据的时候 ,从这个位置 开始 要
conn.setRequestProperty("range", "bytes="
+ alreadyWritePosition + "-" + endIndex);
//要告诉服务器从哪个位置开始写
// raf.seek(alreadyWritePosition);
}else{
conn.setRequestProperty("range", "bytes=" + startIndex
+ "-" + endIndex);
// 要 告诉 从哪个位置开始写
// raf.seek(startIndex);
}
int length=conn.getContentLength();
//获取服务器返回的数据,然后将返回的数据存入这个文件中
RandomAccessFile raf =createRandomAccessFile(getFileName(path), length);
if(alreadyWritePosition!=0){
raf.seek(alreadyWritePosition);
}else{
raf.seek(startIndex);
}
//返回部分数据,如果成功状态码是206
int code = conn.getResponseCode();
//将获得的数据写入文件中:
if(code==206){
InputStream in = conn.getInputStream();
//读取数据
int len=0;
byte[] buffer=new byte[1024];
while((len=in.read(buffer))>0){
raf.write(buffer, 0, len);
String context=threadId+","+ new String(buffer)+","+startIndex+","+endIndex;
//记录实时位置并写入 threadId.postion文件中
currentPosition=currentPosition+len;
// File info = new File(threadId + ".position");
// RandomAccessFile rf = new RandomAccessFile(info, "rwd");
RandomAccessFile rf =createRandomAccessFile(threadId + ".position",5);
rf.write(String.valueOf(currentPosition).getBytes());
rf.close();
}
}
// System.out.println("第 " + threadId + "线程 下载 结束 了 ");
Log.i("out", "第 " + threadId + "线程 下载 结束 了 ");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public int getPositionInFile(File file){
int readPosition=0;
try {
BufferedReader bfr=new BufferedReader(new FileReader(file));
String context=bfr.readLine();
readPosition=Integer.valueOf(context);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return readPosition;
}
}
}