//开始下载文件
package multithread_download2;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class StartDownload
{
private DownloadBean bean;//封装下载参数信息实体
private File positionFile;//记录下载位置文件
private long[] startPos;//开始位置
private long[] endPos;//结束位置
private static int sleepTime=500;//每隔0.5秒向记录下载位置的缓存文件写入各个下载线程当前的下载位置
private DownloadThread[] downloadThread;//用于下载文件的线程数组
private int fileLength;//资源文件长度
@SuppressWarnings("unused")
private boolean first=true;//是否刚开始下载,如果不是刚开始下载则为false(即已经开始下载且暂停过)
private boolean stop=false;//下载结束标志
public StartDownload(DownloadBean bean)//构造方法
{
this.bean=bean;
String posFilepath=this.bean.getSavePath();//下载位置缓存文件的路径
String posFilename=this.bean.getSaveFilename()+".position";//缓存文件的文件名
positionFile=new File(new File(posFilepath),posFilename);//创建缓存文件,用于记录下载位置
if(positionFile.exists())//如果缓存文件已经存在,表明之前已经下载过一部分
{
first=false;
readDownloadPosition();//读取缓存文件中的下载位置,即每个下载线程的开始位置和结束位置,将读取到的下载位置写入到开始数组和结束数组
}
else//如果是刚开始下载
{
getDownloadPosition();//获取下载位置
}
}
public void startDownload()//开始下载
{
if (!stop)
{
downloadThread = new DownloadThread[startPos.length];//创建下载线程数组,每个下载线程负责各自的文件块下载
for (int i = 0; i < startPos.length; i++)
{
downloadThread[i] = new DownloadThread(bean.getSourceUrl(), bean.getSavePath() + File.separator + bean.getSaveFilename(), startPos[i], endPos[i], i );
downloadThread[i].start();//启动线程,开始下载
System.out.println("线程"+i+"开始下载");
}
while (!stop) //向缓存文件循环写入下载文件位置信息
{
try
{
writeDownloadPosition();//更新下载位置信息
Thread.sleep(sleepTime);//每隔0.5秒更新一次下载位置信息
stop = true;
}
catch (InterruptedException e)
{
e.printStackTrace();
}
for (int i = 0; i < startPos.length; i++)//判断是否所有下载线程都执行结束
{
if (!downloadThread[i].isDownloadOver())
{
stop = false;//只要有一个下载线程没有执行结束,则文件还没有下载完毕
break;
}
}
}
positionFile.delete();//删除下载位置缓存文件
System.out.println("所有下载线程执行完毕,文件下载完成");
}
}
public void writeDownloadPosition()//更新下载位置缓存文件的下载位置
{
try
{
DataOutputStream dos = new DataOutputStream(new FileOutputStream(positionFile));
dos.writeInt(startPos.length);
for (int i = 0; i < startPos.length; i++)
{
dos.writeLong(downloadThread[i].getStartPos());
dos.writeLong(downloadThread[i].getEndPos());
}
dos.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
private void getDownloadPosition()//获取下载位置(刚开始下载的情况)
{
startPos=new long[bean.getThreadNum()];//创建开始位置数组
endPos=new long[bean.getThreadNum()];//创建结束位置数组
fileLength = this.getFileSize();//获取文件长度
if (fileLength == -1)
{
stop = true;
}
else if (fileLength == -2)
{
stop = true;
}
else if (fileLength > 0)
{
for (int i = 0, len = startPos.length; i < len; i++)
{
int size = i * (fileLength / len);
startPos[i] = size;
//设置最后一个结束点的位置
if (i == len - 1)
{
endPos[i] = fileLength;
}
else
{
size = (i + 1) * (fileLength / len);
endPos[i] = size;
}
}
}
else
{
stop = true;
}
}
private void readDownloadPosition()//读取已经存在的缓存文件中的下载位置
{
try
{
DataInputStream dis = new DataInputStream(new FileInputStream(positionFile));
int startPosLength = dis.readInt();//获取下载位置的数目,即有多少个开始位置,多少个结束位置
startPos = new long[startPosLength];
endPos = new long[startPosLength];
for (int i = 0; i < startPosLength; i++)//获取开始位置数组和结束位置数组
{
startPos[i] = dis.readLong();
endPos[i] = dis.readLong();
}
dis.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
private int getFileSize()//获取文件大小
{
int fileLength = -1;
try {
URL url = new URL(this.bean.getSourceUrl());//获取资源路径
HttpURLConnection conn = (HttpURLConnection) url.openConnection();//创建URL连接
int stateCode = conn.getResponseCode();//获取响应信息
if (stateCode != HttpURLConnection.HTTP_OK && stateCode != HttpURLConnection.HTTP_PARTIAL)
{
return -2;
}
else if (stateCode >= 400)
{
return -2;
}
else//响应正常则获取文件长度
{
fileLength = conn.getContentLength();
}
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
return fileLength;//返回文件长度
}
}