`
superhack
  • 浏览: 32066 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

多线程下载与断点续传

阅读更多

一个多线程下载与断点续传的demo...

 

import java.io.*;
import java.net.*;
import java.util.concurrent.*;

public class Downloader3 {
	URL url;
	File des;
	File cfg;
	long size;
	long sum;
	int taskNum = 10;
	CountDownLatch latch;
	String path = "C:/Documents and Settings/Administrator/桌面/";

	class Task extends Thread {
		int id;
		long start;
		long end;
		boolean error;
		int errTimes;

		public Task(int id, long start, long end) {
			this.id = id;
			this.start = start;
			this.end = end;
		}

		public void run() {
			for (long now = start ; now <= end; ) {
				if (error) {
					if (++errTimes > 5) {
						latch.countDown();
						System.err.format("Task%2d ERROR\n", id);
						return;
					}
					sum -= now - start;
					now = start;
					error = false;
				}
				System.out.format("Task%2d: [%d, %d]\n", id, now, end);
				try {
					HttpURLConnection con = (HttpURLConnection) url.openConnection();
					con.setRequestProperty("RANGE", "bytes=" + now + "-" + end);
					int code = con.getResponseCode();
					if (code / 100 != 2) {
						System.err.format("Task%2d ERROR: %d\n", id, code);
						throw new IOException();
					}
					byte[] buf = new byte[4096];
					InputStream is = con.getInputStream();
					BufferedInputStream bis = new BufferedInputStream(is);
					RandomAccessFile fos = new RandomAccessFile(des, "rw");
					RandomAccessFile raf = new RandomAccessFile(cfg, "rw");
					fos.seek(now);
					for (int len = -1; (len = bis.read(buf)) != -1; ) {
						fos.write(buf, 0, len);
						sum += len;
						now += len;
						raf.seek(8);
						raf.writeLong(sum);
						raf.seek(20 + id * 24 + 16);
						raf.writeLong(now);
						System.out.format("%.2f%%\n", sum * 100.0 / size);
					}
					fos.close();
					raf.close();
					bis.close();
					con.disconnect();
				} catch (IOException e) {
					e.printStackTrace();
					error = true;
					try {
						TimeUnit.SECONDS.sleep(3);
					} catch (InterruptedException e1) {
						e1.printStackTrace();
					}
					continue;
				}
			} // end for
			latch.countDown();
		}
		
	}

	public void download(String address) {
		long begin = System.currentTimeMillis();
		String name = address.substring(address.lastIndexOf('/') + 1);
		des = new File(path + name + ".tmp");
		cfg = new File(path + name + ".cfg");
		latch = new CountDownLatch(taskNum);
		ExecutorService exec = Executors.newCachedThreadPool();
		long[] starts = new long[taskNum];
		long[] ends = new long[taskNum];
		try {
			url = new URL(address);
			analyse(starts, ends);
			for (int i = 0; i < taskNum; i++)
				exec.execute(new Task(i, starts[i], ends[i]));
			latch.await();
			exec.shutdown();
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (sum >= size) {
			des.renameTo(new File(path + name));
			cfg.delete();
		}
		long time = System.currentTimeMillis() - begin;
		System.out.format("Time: %.2fs, Speed: %.2fk/s\n",
							0.001 * time, 0.9765625 * size / time);
	}

	private void analyse(long[] starts, long[] ends) throws IOException {
		RandomAccessFile raf = new RandomAccessFile(cfg, "rw");
		if (!des.exists()) {
			HttpURLConnection con = (HttpURLConnection) url.openConnection();
			size = con.getContentLength();
			long part = size / taskNum;
			raf.writeLong(size);
			raf.writeLong(sum);
			raf.writeInt(taskNum);
			for (int i = 0; i < taskNum; i++) {
				starts[i] = part * i;
				ends[i] = (i == taskNum - 1) ? size - 1 : part * (i + 1) - 1;
				raf.writeLong(starts[i]);
				raf.writeLong(ends[i]);
				raf.writeLong(starts[i]); // now
			}
		} else {
			size = raf.readLong();
			sum = raf.readLong();
			taskNum = raf.readInt();
			for (int i = 0; i < taskNum; i++) {
				raf.seek(20 + i * 24 + 8);
				ends[i] = raf.readLong();
				starts[i] = raf.readLong();
			}
		}
		raf.close();
	}

	public static void main(String[] args) {
		Downloader3 d = new Downloader3();
		String address = "http://cidian.youdao.com/download/YoudaoDict.exe";
		d.download(address);
	}

}

  

总结:

1. "RANGE"属于闭区间类型, 对右端点值不好理解可以通过干脆不写来变通, 如果区间不合理会导致下载文件空洞...

2. 每个下载子线程对主文件和配置文件的访问要定义局部的RandomAccessFile, 否则会有线程错误...

3. 关闭配置文件的全部RandomAccessFile流, 否则会导致下载完成时删除配置文件失败...

4. 程序处理异常部分极度ugly, 怎么改也是难看...

5. 已用下载时间, 平均下载速度统计信息用专门的线程来做统计比较好...

6. 没实现各种运行参数的灵活设置...

7. 非首次运行时线程调度部分实现的不合理, 难以实现高效下载...

8. 对网络, 线程, IO的API远不够熟悉, 难以实现灵活合理的运用. 也许使用NIO性能会好点儿?

 

分享到:
评论
1 楼 宫庆义 2010-03-26  
  呵呵,  不错!   (终于通过那个论坛测验, 拥有回复权限了!)

相关推荐

    Http多线程下载与断点续传分析

    在实际开发中,我们还可以使用现有的工具,如迅雷、Internet Download Manager等,它们已经内置了多线程下载和断点续传功能,开发者可以通过API或者学习其源码来理解并实现类似的功能。 总之,HTTP多线程下载和断点...

    多线程下载支持断点续传

    在IT领域,多线程下载和断点续传是提高下载效率和用户体验的重要技术。这里,我们将深入探讨这两个概念,并结合使用HttpURLConnection实现的多线程下载工具进行讲解。 首先,多线程下载是一种利用网络资源的方式,...

    基于HTTP协议的多线程下载he断点续传的实现.

    基于HTTP协议的多线程下载he断点续传的实现.基于HTTP协议的多线程下载he断点续传的实现.基于HTTP协议的多线程下载he断点续传的实现.基于HTTP协议的多线程下载he断点续传的实现.基于HTTP协议的多线程下载he断点续传的...

    java 多线程下载和断点续传

    ### Java多线程下载与断点续传技术详解 #### 一、背景介绍 随着互联网技术的发展,数据传输成为日常开发中的重要环节之一。在实际应用中,常常需要下载大文件,例如视频、大型应用程序等。传统的单线程下载方式在...

    Http多线程与断点续传的Dll+源码

    在IT行业中,网络数据传输是不可或缺的一部分,尤其是在大文件下载时,多线程技术和断点续传技术的应用显得尤为重要。本文将深入解析标题为“Http多线程与断点续传的Dll+源码”的技术内容,以及如何利用提供的Dll库...

    MyNetAnts.rar_HTTP协议_多线程下载_断点续传_断点续传和多线程下载

    《MyNetAnts.rar:HTTP协议、多线程下载与断点续传解析》 HTTP协议,全称为HyperText Transfer Protocol,是互联网上应用最为广泛的一种网络协议,它定义了客户端(浏览器)和服务器之间数据交换的标准格式和交互...

    Android多线程文件夹下载及断点续传

    在实现多线程下载和断点续传时,还需要注意以下几点: - **异常处理**:网络中断、文件I/O错误等异常情况需要妥善处理,确保能够恢复下载。 - **线程同步**:在多线程环境下,需要确保线程安全,防止数据竞争和不...

    Android之多线程下载及断点续传

    在Android开发中,多线程下载和断点续传是两个关键的概念,它们极大地提高了应用程序在处理大文件,如音频、视频或应用安装包时的性能和用户体验。下面将详细介绍这两个概念及其应用。 **一、多线程下载** 1. **多...

    HTTP及FTP多线程下载和断点续传

    本文将深入探讨这两个协议在实现多线程下载和断点续传方面的技术细节。 首先,HTTP(超文本传输协议)是用于从Web服务器传输数据的标准协议。在多线程下载中,HTTP允许客户端同时发起多个请求来获取同一文件的不同...

    多线程下载断点续传

    多线程下载与断点续传是现代网络应用中常见的技术,尤其在处理大文件下载时,能够显著提高效率和用户体验。以下将详细介绍这两个概念及其实施细节。 **多线程下载** 多线程下载是指利用多个并发的网络连接来同时从...

    多线程多任务断点续传下载

    在Android开发中,多线程多任务断点续传下载是一项重要的技术,它极大地提高了大文件下载的效率和用户体验。本文将深入解析这一技术,并基于给出的【标题】"多线程多任务断点续传下载"和【描述】中的信息进行详细...

    Java实现多线程下载和断点续传

    1. 把每个下载文件切成若干个块(Block),然后得到一个位图,用来标记每个块的下载情况,并保存到文件里,用于实现断点续传。 2. HTTP Header里增加Range,如果服务器返回Cotent-Range 说明服务器支持文件定位,可以...

    Android开发--多线程下载加断点续传

    1.多线程下载: 首先通过下载总线程数来划分文件的下载区域:利用int range = fileSize / threadCount;得到每一段下载量;每一段的位置是i * range到(i + 1) * rang - 1,注意最后一段的位置是到filesize - 1; ...

    安卓多线程下载,断点续传

    在实际开发中,还需要考虑网络状况的变化、内存管理、用户界面的更新等问题,以确保多线程断点续传功能的稳定性和用户体验。例如,当设备网络切换或电量低时,应用应该能够暂停下载并保存当前进度;在用户界面中,应...

    C#实现支持断点续传多线程下载客户端工具类

    在C#编程中,实现一个支持断点续传和多线程下载的HTTP Web客户端工具类是一项复杂但实用的任务。断点续传允许用户在下载过程中中断,然后在稍后的时间点继续下载,而不会丢失已下载的数据。多线程下载则能显著提高大...

    VC HTTP多线程与断点续传下载示例

    本文将深入探讨在Visual C++(简称VC)环境下实现HTTP协议的多线程下载与断点续传技术,这对于提升大文件下载效率和用户体验至关重要。 HTTP(超文本传输协议)是互联网上应用最广泛的数据通信协议之一,用于从Web...

    多线程下载及断点续传

    在IT领域,多线程下载和断点续传是提高文件下载效率和用户体验的重要技术。这两者结合使用,可以显著优化大文件的下载过程,尤其是对于网络环境不稳定的情况。 首先,我们来理解“多线程”这个概念。线程是操作系统...

    Android版本更新,多线程下载、断点续传(原创)

    Android版本更新实用的Demo,主要用到了HttpURLConnection、Xml PULL解析(其中也提供了JSON格式的解析)、丰富的辅助类、多线程下载与断点续传,界面虽然丑点但比较实用。如果你下载了该资源无法运行的话,别急着...

    Java 多线程下载及断点续传示例

    在Java编程中,多线程下载和断点续传是两个关键的概念,它们在处理大文件下载时尤其重要。这两个技术结合使用可以显著提高下载效率并优化用户体验。 **多线程下载** 多线程下载是一种将文件分割成多个部分,然后...

Global site tag (gtag.js) - Google Analytics