今天学习了一些http多线程下载,简单整理一下,便于今后查阅。
URLConnection 可以很方便的与指定的站点交换信息,URLConnect有个子类:HttpURLConnection,HttpURLConnection增加了一些操作http资源的便捷方法。
实现多线程下载步骤如下:
1)创建URL对象。
2)获取指定URL对象所指定资源的大小,使用getContentlength方法。
3)计算每个线程要下载资源的哪个部分(从某个字节开始到哪个字节介绍)。
4)依次创建线程,启动多线程来下载网络指定的部分。
代码如下:
创建downloadUitl类,来创建HttpURLConnetion对象,获取下载资源的大小,创建多线程,来下载指定部分的内容
package com.example.mutidownload;
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 android.app.DownloadManager;
public class DownloadUntil {
//set path of resource
String path; //记录资源路径
private int threadNum; //保存下载文件的大小
private long fileSize; //保存下载文件的大小
private String targeFile; //下载文件的本地位置
DownloadThread[] threads; //线程池
public DownloadUntil(String targeFile, int threadNum,String path) {
// TODO Auto-generated constructor stub
this.path = path;
this.threadNum = threadNum;
this.targeFile = targeFile;
threads = new DownloadThread[threadNum];
}
//多线程下载的核心代码
public void download() throws IOException{
URL url = new URL(path);
//build http header
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(10000);
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "image/gif,image/jpeg,*/*");
conn.setRequestProperty("Accept-Language", "zh-CN");
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("User-Agent", "Mozilla/4.0(compatible;MSIE6.0;Windows NT 5.0)");
conn.setRequestProperty("Connect", "Keep-Alive");
fileSize = conn.getContentLength(); //获取下载下载文件大小
conn.disconnect();
long currentPartSize = fileSize/threadNum; //计算每个线程要下载的文件大小
RandomAccessFile file = new RandomAccessFile(targeFile, "rw");//打开本地文件,来保存下载数据
file.setLength(fileSize);
file.close();
//创建多线程
for(int i = 0; i< threadNum; i++){
long startPos = i*currentPartSize; //计算每个线程所要下载资源的起始位置
RandomAccessFile currentPart = new RandomAccessFile(targeFile, "rw");
currentPart.seek(startPos);//set download focus in local file
threads[i] = new DownloadThread(startPos,currentPartSize,currentPart);//create thread
threads[i].start();
}
}
//download rate
public float getDownloadProgress(){
int sumSize = 0;
for (int i = 0; i < threads.length; i++) {
sumSize += threads[i].length;
}
return (float) (sumSize * 1.0/fileSize * 1.0);
}
//create download thread
private class DownloadThread extends Thread{
public int length = 0; //记录此线程已下载资源的长度
private long startPos; //在下载流中,此线程要下载的初始位置
private long currentPartSize; //此线程下载内容的总长度
private RandomAccessFile currentPart;//本地文件句柄
public DownloadThread(long startPos, long currentPartSize,
RandomAccessFile currentPart) {
// TODO Auto-generated constructor stub
this.startPos = startPos;
this.currentPart = currentPart;
this.currentPartSize = currentPartSize;
}
// 单个下载和数据读写的核心代码
public void run(){
try {
//creat url connect
URL url = new URL(path);
HttpURLConnection httpConn = (HttpURLConnection)url.openConnection();
//set header
httpConn.setConnectTimeout(10000);
httpConn.setRequestMethod("GET");
httpConn.setRequestProperty("Accept", "image/gif,image/jpeg,*/*");
httpConn.setRequestProperty("Accept-Language", "zh-CN");
httpConn.setRequestProperty("Charset", "UTF-8");
httpConn.setRequestProperty("User-Agent", "Mozilla/4.0(compatible;MSIE6.0;Windows NT 5.0)");
httpConn.setRequestProperty("Connect", "Keep-Alive");
InputStream is = httpConn.getInputStream();//get inputstream
is.skip(startPos); //把流中的索引指定到此线程所要下载的位置
byte[] buffer = new byte[1024];
int hasRead = 0;
while (length < currentPartSize &&
(hasRead = is.read(buffer)) != -1) {
currentPart.write(buffer, 0, hasRead); //把流中数据写入到本地文件中(在前面已经指定了文件索引,所以在此直接保存就可以
length+=hasRead;
}
currentPart.close();
is.close();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Activity端测试代码:
package com.example.mutidownload;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
public class MainActivity extends Activity {
int mProgress = 0;
ProgressBar progress;
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
if (msg.what == 0x01) {
progress.setProgress(mProgress);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText url = (EditText)findViewById(R.id.url);
progress = (ProgressBar)findViewById(R.id.progress);
Button download = (Button)findViewById(R.id.download);
download.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
final DownloadUntil donwloadUntil = new DownloadUntil(url.getText().toString(), 5, "mnt/sd/download");
try {
donwloadUntil.download();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
mProgress = (int)donwloadUntil.getDownloadProgress()* 100;
handler.sendEmptyMessage(0x01);
if (mProgress > 100) {
timer.cancel();
}
}
}, 0, 100);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
本文详细介绍了如何使用Java的HttpURLConnection实现多线程下载技术,包括创建URL对象、获取资源大小、分配任务给线程以及核心代码实现。通过多线程并行下载,显著提高了下载效率。

3786

被折叠的 条评论
为什么被折叠?



