java 实现一个多线程下载程序,暂时还有部分bug需要修改,先做些笔记
将网络资源Resource .划分成不通的part对象,然后用不通线程去下载part 最后下载完的线程负责合并文件
其实这个过程还有很多优化的地方,能否三个线程同时合并文件,同时删除下载的附件,或者不生成这么多的临时文件,还可以改进成断点下载,还可以写一个爬虫
获得很多url 然后批量下载之类。
先贴下暂时的代码 设计到一些细节的东西,
UUID 之前没遇到过的
package download.object;
import java.io.RandomAccessFile;
import java.util.UUID;
public class Part {
private int begin;
// 下载总长度
private int length;
// 已下载长度
private int currentLength;
//
private String partName;
/**
* 构造Part对象
* @param begin
* @param length
* @param currentLength
*/
public Part(int begin,int length,int currentLength){
this.begin=begin;
this.length=length;
this.currentLength=currentLength;
this.partName=UUID.randomUUID().toString()+".part";
}
public int getBegin() {
return begin;
}
public void setBegin(int begin) {
this.begin = begin;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getCurrentLength() {
return currentLength;
}
public void setCurrentLength(int currentLength) {
this.currentLength = currentLength;
}
public String getPartName() {
return partName;
}
public void setPartName(String partName) {
this.partName = partName;
}
}
Resource.java
package download.object;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
public class Resource {
private List<Part> parts ;
private int threadNum;
private String id;
private String url;
private String savePath;
private String saveFileName;
private Date startDate;
private float costTime;
private float spareTime;
private int size;
public int getCurrentLength(){
int result=0;
for(Part part:parts){
result+=part.getCurrentLength();
}
return result;
}
public int getSize() throws IOException {
if(size==0){
URL u=new URL(url);
size=u.openConnection().getContentLength();
}
return size;
}
public List<Part> getParts() {
return parts;
}
public void setParts(List<Part> parts) {
this.parts = parts;
}
public int getThreadNum() {
return threadNum;
}
public void setThreadNum(int threadNum) {
this.threadNum = threadNum;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getSavePath() {
return savePath;
}
public void setSavePath(String savePath) {
this.savePath = savePath;
}
public String getSaveFileName() {
return saveFileName;
}
public void setSaveFileName(String saveFileName) {
this.saveFileName = saveFileName;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public float getCostTime() {
return costTime;
}
public void setCostTime(float costTime) {
this.costTime = costTime;
}
public float getSpareTime() {
return spareTime;
}
public void setSpareTime(float spareTime) {
this.spareTime = spareTime;
}
public Resource(String url,String savePath,String saveFileName,int threadNum){
this.id=UUID.randomUUID().toString();
this.url=url;
this.savePath=savePath;
this.saveFileName=saveFileName;
this.threadNum=threadNum;
this.parts=new ArrayList<Part>();
}
}
DownloadThread.java
package download.thread;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import download.object.Part;
import download.object.Resource;
import download.util.FileUtil;
public class DownloadThread extends Thread{
private Resource rs;
private Part p;
private RandomAccessFile raf ;
public DownloadThread(Resource rs,Part p ,RandomAccessFile raf){
this.rs=rs;
this.p=p;
this.raf=raf;
}
@Override
public void run() {
try {
if(p.getCurrentLength()>=p.getLength()){
return;
}
int begin=p.getBegin()+p.getCurrentLength();
int end=p.getBegin()+p.getLength();
System.out.println(getName()+":"+begin+" "+end);
URL url=new URL(rs.getUrl());
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
conn.addRequestProperty("Range", "bytes="+begin+"-"+end);
int temp=0;
byte[] buffer=new byte[1024];
InputStream is=url.openStream();
raf.seek(begin);
while((temp=is.read(buffer))!=-1){
raf.write(buffer,0,temp);
p.setCurrentLength(p.getCurrentLength()+temp);
}
if (isFinished(rs)){
mergeFile(rs);
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
}
private void mergeFile(Resource rs) throws IOException {
OutputStream out=new FileOutputStream(new File(rs.getSavePath()+File.separator+rs.getSaveFileName()));
InputStream in=null;
System.out.println("合并图片");
byte[] buf=new byte[1024];
int tempRead=0;
for(Part part:rs.getParts()){
File raf=FileUtil.getPartFile(rs, part);
in=new FileInputStream(raf);
while((tempRead=in.read(buf))!=-1){
out.write(buf,0,tempRead);
}
}
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
}
private boolean isFinished(Resource rs) throws IOException {
if(rs.getCurrentLength()>=rs.getSize()){
return true;
}
return false;
}
}
DownloadHandler.java
package download.thread;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import download.object.Part;
import download.object.Resource;
public class DownloadHandler {
public void doDownload(Resource rs){
try {
int preLength=rs.getSize()/rs.getThreadNum()+1;
for(int i=0;i<rs.getThreadNum();i++){
int length=preLength;
if(i==rs.getThreadNum()-1){
length=rs.getSize()-i*preLength;
}
System.out.println(length);
Part p =new Part(i*preLength,length, 0);
rs.getParts().add(p);
RandomAccessFile raf=new RandomAccessFile(rs.getSavePath()+File.separator+p.getPartName(),"rw");
new DownloadThread(rs,p,raf).start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
FileUtil
package download.util;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import download.object.Part;
import download.object.Resource;
public class FileUtil {
public static File getPartFile(Resource rs,Part p){
return new File(rs.getSavePath()+File.separator+p.getPartName());
}
public static void deletePartFile(Resource rs) throws IOException{
for(Part part:rs.getParts()){
File file= getPartFile(rs,part);
System.out.println(file.getName());
if(!file.exists()) continue;
// delete
}
}
}