黑马程序员技术交流社区
标题:
自定义的多线程下载程序为什么有时候会下载不完!
[打印本页]
作者:
张贺
时间:
2014-3-24 17:09
标题:
自定义的多线程下载程序为什么有时候会下载不完!
自己弄的个多线程下载的程序,为什么有时候可以下载完全,有时候会卡在一个地方不动?下载代码如下:
import java.io.*;
import java.net.*;
/*
需求:自定义设计多线程下载工具类
思路:
1,先通过URL对象获取到需下载的内容的地址并连接到指定URL获取文件信息
2,计算所需下载文件的大小,并按照需要(线程数)将文件等分
3,创建多个线程,每个线程都会负责相应的下载部分(主要利用RandomAccessFile类的任意存储特点)
4,进行测试
*/
public class DownLoad
{
//定义下载资源的路径
private String path;
//指定下载的文件的保存位置
private String targetFile;
//定义需要使用多少个线程下载资源
private int threadNum;
//定义下载的线程对象
private DownThread[] threads;
//定义文件的总大小
private long fileSize;
//定义构造器,初始化资源路径,线程数等字段
public DownLoad(String path,String targetFile,int threadNum)
{
this.path=path;
this.targetFile=targetFile;
this.threadNum=threadNum;
//初始化trheads数组
threads=new DownThread[threadNum];
}
//定义方法,用以获取下载文件的相关信息,并根据线程数将文件进行等分
public void download()throws Exception
{
//定义并初始化指定路径的URL对象
URL url=new URL(path);
//通过URL对象获取对指定路径的连接
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
//设置连接超时属性
conn.setConnectTimeout(5*1000);
//设置连接请求方式
conn.setRequestMethod("GET");
//设置请求的接收文件的相关属性
conn.setRequestProperty("Accept","*/*");
conn.setRequestProperty("Accept-Language","zh-CN");
conn.setRequestProperty("Charset","UTF-8");
conn.setRequestProperty("Connection","Keep-Alive");
//得到文件的大小
fileSize=conn.getContentLength();
conn.disconnect();
//按线程数将文件等分
long partSize=fileSize/threadNum+1;
//使用指定文件创建RandomAccessFile对象
RandomAccessFile file=new RandomAccessFile(targetFile,"rw");
//设置本地文件的大小
file.setLength(fileSize);
file.close();
//创建并启动线程
for(int i=0;i<threadNum;i++)
{
//计算每个线程下载的开始位置
long startPos=i*partSize;
//每个线程使用一个RandomAccessFile进行下载
RandomAccessFile part=new RandomAccessFile(targetFile,"rw");
//设置下载位置
part.seek(startPos);
//创建下载线程
threads[i]=new DownThread(startPos,partSize,part);
//启动线程
threads[i].start();
}
}
//定义方法用于获取下载完成的百分比
public double getComplete()
{
//统计所有线程已经下载的大小的总和
int sumSize=0;
for(int i=0;i<threadNum;i++)
{
sumSize+=threads[i].length;
}
//返回已完成的百分比
return sumSize*1.0/fileSize;
}
//测试代码
public String getCompletes()
{
//统计所有线程已经下载的大小的总和
int sumSize=0;
for(int i=0;i<threadNum;i++)
{
sumSize+=threads[i].length;
}
//返回已完成的百分比
return fileSize+" "+threads[0].length+" "+threads[1].length+" "+threads[2].length+"
"+threads[3].length+" "+(sumSize*1.0/fileSize);
}
//定义内部线程类,用于下载文件
private class DownThread extends Thread
{
//当前线程的下载位置
private long startPos;
//定义当前线程负责下载的文件大小
private long partSize;
//定义下载用的文件对象
private RandomAccessFile part;
//计算已经下载的文件大小
public long length=0;
//定义构造器,初始化数据
public DownThread(long startPos,long partSize,RandomAccessFile part)
{
this.startPos=startPos;
this.partSize=partSize;
this.part=part;
}
//重写run方法
public void run()
{
try
{
//定义并初始化指定路径的URL对象
URL url=new URL(path);
//通过URL对象获取对指定路径的连接
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
//设置连接超时属性
conn.setConnectTimeout(5*1000);
//设置连接请求方式
conn.setRequestMethod("GET");
//设置请求的接收文件的相关属性
conn.setRequestProperty("Accept","*/*");
conn.setRequestProperty("Accept-Language","zh-CN");
conn.setRequestProperty("Charset","UTF-8");
//获取文件输入流
InputStream inStream=conn.getInputStream();
//跳过startPos个字节(只下载自己负责的部分)
inStream.skip(startPos);
//定义字节数组,保存数据
byte[] buf=new byte[1024];
int hasRead=0;
//读取网络数据,并写入本地文件
while(length<partSize&&(hasRead=inStream.read(buf))!=-1)
{
//将数据写入指定文件的指定位置
part.write(buf,0,hasRead);
//累计下载的总大小
length+=hasRead;
this.yield();
}
part.close();
inStream.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
复制代码
测试代码如下:
import java.lang.Math;
/*
测试程序
*/
public class DownTest
{
public static void main(String[] args)throws Exception
{
//初始化DownLoad对象
final DownLoad download=new DownLoad
("http://zhangmenshiting.baidu.com/data2/music/57130533/73007331395604861128.mp3?
xcode=b453c78019aaef462150ccef90c23ba01489e1db000d3934","测试.mp3",4);
//开始下载
download.download();
//定义线程,每过0.1秒统计任务的完成度
new Thread()
{
public void run()
{
while(download.getComplete()<1)
{
System.out.println("已完成:"+download.getComplete());
try
{
Thread.sleep(1000);
}
catch(Exception e){}
}
}
}.start();
}
}
复制代码
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2