Chinaunix首页 | 论坛 | 博客
  • 博客访问: 648955
  • 博文数量: 632
  • 博客积分: 39960
  • 博客等级: 大将
  • 技术积分: 4975
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-16 18:20
文章分类

全部博文(632)

文章存档

2011年(1)

2008年(631)

我的朋友

分类:

2008-10-16 18:22:53

    工具我想没有几个人不会用的吧,前段时间比较无聊,花了点时间用java写了个简单的http多线程程序,纯粹是无聊才写的,只实现了几个简单的功能,而且也没写界面,今天正好也是一个无聊日,就拿来写篇文章,班门弄斧一下,觉得好给个掌声,不好也不要喷,谢谢!

    我实现的这个http工具功能很简单,就是一个多线程以及一个断点恢复,当然下载是必不可少的。那么大概先整理一下要做的事情:

    1、 连接资源,获取资源信息,创建文件

    2、 切分资源,多线程下载

    3、 断点恢复功能

    4、 下载速率统计

String urlStr = “”;     //资源地址
URL url = new URL(urlStr);    //创建URL
URLConnection con = url.openConnection();               //建立连接
contentLen = con.getContentLength();                    //获得资源长度
9File file = new File(filename);    //根据filename创建一个下载文件,也会是我们最终下载所得的文件

    很简单吧,没错就是这么简单,第一步做完了,那么接下来要做第二步,切分资源,实现多线程。在上一步我们已经获得了资源的长度contentLen,那么如何根据这个对资源进行切分呢?假如我们要运行十个线程,那么我们就先把contentLen处以10,获得每块的大小,然后在分别创建十个线程,每个线程负责其中一块的写入,这就需要利用到RandomAccessFile这个类了,这个类提供了对文件的随机访问,可以指定向文件中的某一个位置进行写入操作,大致代码如下:

long subLen = contentLen / threadQut;                           //获取每块的大小
//创建十个线程,并启动线程
for (int i = 0; i < threadQut; i++) {
DLThread thread = new DLThread(this, i + 1, subLen * i, subLen * (i + 1) - 1); //创建线程
QSEngine.pool.execute(dlThreads[i]);                                //把线程交给线程池进行管理
}

    在这里使用到了DLThread这个类,我们先来看看这个类的构造方法的定义:

    public DLThread(DLTask dlTask, int id, long startPos, long endPos)

    第一个参数为一个DLTask,这个类就代表一个下载任务,里面主要保存这一个下载任务的信息,包括下载资源名,本地文件名等等的信息。第二个参数就是一个标示线程的id,如果有10个线程,那么这个id就是从1到10,第三个参数startPos代表该线程从文件的哪个地方开始写入,最后一个参数endPos代表写到哪里就结束。

    我们再来看看,一个线程启动后,具体如何去下载,请看run方法:

public void run() {
System.out.println("线程" + id + "启动");
BufferedInputStream bis = null;          //创建一个buff
RandomAccessFile fos = null;
byte[] buf = new byte[BUFFER_SIZE];        //缓冲区大小
URLConnection con = null;
try {
con = url.openConnection();      //创建连接,这里会为每个线程都创建一个连接
con.setAllowUserInteraction(true);
if (isNewThread) {
con.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);//设置获取资源数据的范围,从startPos到endPos
fos = new RandomAccessFile(file, "rw");   //创建RandomAccessFile
fos.seek(startPos);          //从startPos开始
} else {
con.setRequestProperty("Range", "bytes=" + curPos + "-" + endPos);
fos = new RandomAccessFile(dlTask.getFile(), "rw");
fos.seek(curPos);
 }
//下面一段向根据文件写入数据,curPos为当前写入的未知,这里会判断是否小于endPos,
//如果超过endPos就代表该线程已经执行完毕
bis = new BufferedInputStream(con.getInputStream());
while (curPos < endPos) {
int len = bis.read(buf, 0, BUFFER_SIZE);
if (len == -1) {
break;
}
fos.write(buf, 0, len);
curPos = curPos + len;
if (curPos > endPos) {
readByte += len - (curPos - endPos) + 1; //获取正确读取的字节数
} else {
readByte += len;
}
}
System.out.println("线程" + id + "已经下载完毕。");
this.finished = true;
bis.close();
fos.close();
} catch (IOException ex) {
ex.printStackTrace();
throw new RuntimeException(ex);
}
}

[1]   

【责编:Chuan】

--------------------next---------------------

阅读(567) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~