`
kinkding
  • 浏览: 150643 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

多线程断点续传

    博客分类:
  • JAVA
阅读更多
package mydown;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
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.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 多线程断点续传
 * 
 * @author kinkding
 * @history 2009-7-25
 */
public class TestMyDown {

	int threads;
	String rootPath = "F:/mydown";
	String fileName = "";
	URL downUrl;
	CountDownLatch latch;

	public TestMyDown(String strUrl, int threads) throws MalformedURLException {
		downUrl = new URL(strUrl);
		this.threads = threads;
		fileName = strUrl.substring(strUrl.lastIndexOf('/') + 1);
		latch = new CountDownLatch(threads);
	}

	public int run() throws IOException {
		// 创建根路径
		File rootFile = new File(rootPath);
		if (!rootFile.exists()) {
			rootFile.mkdirs();
		}

		HttpURLConnection urlConn = (HttpURLConnection) downUrl.openConnection();
		this.setHeader(urlConn);
		long totalLength = urlConn.getContentLength();
		long threadLength = totalLength / threads;
		// 设置断点
		long startPos[] = this.setBreakPoint(totalLength);
		// 开始进行多线程下载
		DownThread downThreads[] = new DownThread[threads];
		ExecutorService exec = Executors.newCachedThreadPool();
		for (int i = 0; i < threads; i++) {
			startPos[i] += threadLength * i;
			long endPos = i == threads - 1 ? totalLength : (threadLength * (i + 1) - 1);
			// 开启子线程并执行
			DownThread child = new DownThread(startPos[i], endPos, i);
			downThreads[i] = child;
			exec.execute(child);
		}
		try {
			// 等待所有线程下载完成
			latch.await();
			exec.shutdown();
			// 开始合并文件
			this.mergeFile(downThreads);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		return 1;
	}

	private long[] setBreakPoint(long totalLength) throws IOException {
		long startPos[] = new long[threads];
		File file = new File(this.rootPath + '/' + this.fileName);
		if (file.exists() && file.length() < totalLength) {
			File root = new File(this.rootPath);
			for (File f : root.listFiles()) {
				String name = f.getName();
				long length = f.length();
				if (name != null && length > 0 && name.startsWith(this.fileName + '_')) {
					startPos[Integer.parseInt(name.substring(name.lastIndexOf('_') + 1))] = length;
				}
			}
		} else {
			file.createNewFile();
		}
		return startPos;
	}

	private void mergeFile(DownThread downThreads[]) throws IOException {
		BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(this.rootPath
				+ "/" + this.fileName));
		for (int i = 0; i < threads; i++) {
			BufferedInputStream input = new BufferedInputStream(new FileInputStream(
					downThreads[i].file));
			int len = 0;
			long count = 0;
			byte[] b = new byte[1024];
			while ((len = input.read(b)) != -1) {
				count += len;
				output.write(b, 0, len);
				if ((count % 4096) == 0) {
					output.flush();
				}
			}
			input.close();
			downThreads[i].file.delete();
		}
		output.flush();
		output.close();
		System.out.println(fileName + " ok!");
	}

	private void setHeader(HttpURLConnection urlConn) {
		// 模拟浏览器的访问
		urlConn
				.setRequestProperty("User-Agent",
						"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.1) Gecko/20090715 Firefox/3.5.1");
		urlConn.setRequestProperty("Accept-Language", "zh-cn,zh;q=0.5");
		urlConn.setRequestProperty("Accept-Charset", "GB2312,utf-8;q=0.7,*;q=0.7");
		urlConn.setRequestProperty("Keep-Alive", "300");
		urlConn.setRequestProperty("Connection", "keep-alive");
		urlConn.setRequestProperty("Cache-Control", "max-age=0");
		urlConn.setRequestProperty("Referer", downUrl.getPath());
	}

	class DownThread extends Thread {
		private File file;
		private int id;
		private long startPos;
		private long endPos;

		public DownThread(long startPos, long endPos, int id) {
			super();
			this.startPos = startPos;
			this.endPos = endPos;
			this.id = id;
			file = new File(rootPath + "/" + fileName + "_" + id);
			if (!file.exists()) {
				try {
					file.createNewFile();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		public void run() {
			System.out.println("thread " + id + " start...");
			HttpURLConnection con = null;
			InputStream inputStream = null;
			BufferedOutputStream outputStream = null;
			long count = 0;
			try {
				outputStream = new BufferedOutputStream(new FileOutputStream(file.getPath(), true));
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			while (true) {
				try {
					con = (HttpURLConnection) downUrl.openConnection();
					setHeader(con);
					con.setAllowUserInteraction(true);
					con.setConnectTimeout(1000);
					con.setReadTimeout(1000);

					if (startPos < endPos) {
						// 设置下载数据的起止区间
						System.out.println("thread" + id + " bytes=" + startPos + "-" + endPos);
						con.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
						int code = con.getResponseCode();
						// 服务器是否响应成功
						if (code != HttpURLConnection.HTTP_OK
								&& code != HttpURLConnection.HTTP_PARTIAL) {
							outputStream.close();
							con.disconnect();
							latch.countDown();
							break;
						}

						inputStream = con.getInputStream();
						int len = 0;
						byte[] b = new byte[1024];
						while ((len = inputStream.read(b)) != -1) {
							outputStream.write(b, 0, len);
							count += len;
							startPos += len;
							if (count % 4096 == 0) {
								outputStream.flush();
							}
						}
						outputStream.flush();
						outputStream.close();
						inputStream.close();
						con.disconnect();
					}
					System.out.println("thread " + id + " end.");
					latch.countDown();
					break;
				} catch (IOException e) {
					try {
						outputStream.flush();
						inputStream.close();
						con.disconnect();
						// 2秒后重连
						TimeUnit.SECONDS.sleep(1);
					} catch (InterruptedException e1) {
						e1.printStackTrace();
					} catch (IOException e2) {
						e2.printStackTrace();
					}
					continue;
				}
			}
			// 循环终止
			if (outputStream != null) {
				try {
					outputStream.close();
					con.disconnect();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public static void main(String[] args) {
		String url = "http://i1.sinaimg.cn/dy/hdphoto/2009/0425/U1565P1T557D132F12892DT20090425105719.jpg";
		try {
			TestMyDown mydown = new TestMyDown(url, 4);
			mydown.run();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

 

程序运行结果如下:

thread 0 start...
thread0 bytes=0-46078
thread 1 start...
thread1 bytes=46079-92157
thread 2 start...
thread2 bytes=92158-138236
thread 3 start...
thread3 bytes=138237-184319
thread2 bytes=92158-138236
thread 0 end.
thread1 bytes=74995-92157
thread 1 end.
thread3 bytes=174453-184319
thread 3 end.
thread2 bytes=114648-138236
thread 2 end.
U1565P1T557D132F12892DT20090425105719.jpg ok!

 

分享到:
评论

相关推荐

    android多线程断点续传

    在Android开发中,多线程断点续传是一项重要的技术,尤其在处理大文件下载时。这个技术的主要目的是提高下载效率并确保用户可以中断或恢复下载过程。以下将详细讲解多线程断点续传的概念、实现原理以及在Android中的...

    Android多线程断点续传下载

    在Android应用开发中,实现多线程断点续传下载是一项重要的技术,它涉及到网络编程、文件操作以及并发处理等多个方面。以下将详细介绍这个主题的相关知识点。 首先,我们需要理解“多线程”。在Android系统中,为了...

    FTP、HTTP 多线程断点续传下载文件.rar

    标题中的“FTP、HTTP 多线程断点续传下载文件.rar”暗示了这是一个关于网络协议(FTP和HTTP)在实现多线程下载时如何支持断点续传功能的资源包。这个压缩文件可能包含了一个或者多个示例程序、文档或教程,用于解释...

    c#多线程断点续传

    在提供的压缩包文件中,可能包含了一个名为“download”的示例项目,这可能是用于演示上述多线程断点续传功能的源代码。通过分析和运行这个项目,你可以更直观地理解这两种技术的结合应用。 总之,多线程和断点续传...

    java多线程断点续传下载

    Java多线程断点续传下载是一个复杂但实用的技术,尤其在处理大文件或网络不稳定时,能够提高用户体验并优化资源利用。以下是对这个主题的详细解析: **1. Java多线程** Java多线程是指在一个Java应用程序中同时执行...

    java ftp 多线程 断点续传等知识

    而"多线程"和"断点"这两个文件名可能是指相关示例代码或文档,可以进一步帮助你理解和实践Java FTP的多线程下载和断点续传。 在实际应用中,还需要考虑其他因素,如错误处理、网络状况的监控、文件完整性检查等。...

    android多线程断点续传下载

    在Android开发中,多线程断点续传下载是一项重要的技术,它允许用户在暂停、关闭应用或设备重启后从上次中断的地方继续下载大文件,提高用户体验并节省网络资源。以下将详细介绍这一技术的关键知识点: 1. **多线程...

    Xutils框架进行多线程断点续传(详细注解)

    在这个主题中,我们将专注于使用Xutils实现多线程断点续传的功能,这对于大文件下载尤其重要。 首先,断点续传是一种在网络不稳定或者设备意外断电的情况下,能够从上次中断的位置继续下载的技术。它通过保存已下载...

    多线程断点续传(基于HTTP协议).zip_http 断点上传_http 断点续传_多线程断点续传_断点上传_断点续传

    同时,"【成品】多线程断点续传工具.jar"可能是一个可执行的Java应用程序,它提供了用户界面或者命令行工具,让用户可以方便地进行断点续传的文件上传。 多线程断点续传进一步提高了文件传输的效率。通过将文件分割...

    java多线程断点续传[借鉴].pdf

    总结来说,Java实现的多线程断点续传涉及的技术点包括: 1. 并发编程:使用`ExecutorService`、`CountDownLatch`进行线程管理和同步。 2. 文件操作:分析和合并临时文件,实现断点续传。 3. 网络I/O:通过`...

    Android多线程断点续传下载+在线播放音乐

    在Android应用开发中,实现“多线程断点续传下载+在线播放音乐”涉及到多个关键技术,主要包括网络编程、文件操作、多线程处理、内存管理以及多媒体播放等。以下是对这些知识点的详细阐述: 1. **多线程下载**: ...

    多线程断点续传下载实现

    在Android开发中,多线程断点续传技术是一种提高下载效率并优化用户体验的重要方法。这一技术主要应用于大型文件的下载场景,如游戏、应用程序或高清视频等,它允许用户在下载过程中随时暂停,之后能从中断的地方...

    点对点多线程断点续传的实现

    在点对点网络中实现多线程断点续传,主要涉及以下几个关键技术点: 1. **网络连接与通信协议**:P2P网络通常使用TCP或UDP协议进行通信。TCP保证了数据的可靠传输,适合断点续传,而UDP则提供了更高的传输速度,但...

    java实现FTP多线程断点续传

    ### Java实现FTP多线程断点续传:深入解析与技术要点 在现代软件开发中,数据传输是一项基本且关键的任务,特别是在处理大文件时,断点续传功能显得尤为重要。断点续传允许在网络连接中断后恢复传输,避免了重新...

    Android多线程断点续传下载网络上的音/视频等各种文件

    在Android开发中,实现多线程断点续传下载网络上的音视频文件是一项重要的技能,尤其对于提升用户体验和节省用户流量至关重要。断点续传允许用户在暂停或因网络问题中断下载后,从上次停止的位置继续,而多线程则能...

    一个支持多线程断点续传功能的Android下载工具.zip

    在Android平台上,开发一款支持多线程断点续传功能的下载工具是一项技术挑战,它涉及到网络编程、文件处理以及线程管理等多个方面。这款名为"DownloadHelper"的项目,显然是一个致力于解决这些问题的开源解决方案。 ...

    安卓多线程断点续传

    在安卓开发中,多线程断点续传是一项重要的技术,尤其在处理大文件下载时,它可以提高下载效率,同时确保在下载过程中如果中断,可以从上次停止的地方继续,避免了数据的重复下载。本文将详细讲解安卓多线程断点续传...

Global site tag (gtag.js) - Google Analytics