当前位置:首页 » JAVA技术教程

java,多线程下载

2014-02-23 15:15 本站整理 浏览(5)

/**
 * 多线程下载的测试类
 */

public class Demo {
	public static int threadCount = 3;
	
	
	public static int runningThread = 3 ;

	public static void main(String[] args) throws Exception {
		// 1.连接服务器 , 获取一个文件, 获取文件的长度, 在本地创建一个大小跟服务器文件一样大的临时文件
		String path = "http://192.168.1.100:8080/360.exe";
		URL url = new URL(path);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setConnectTimeout(5000);
		conn.setRequestMethod("GET");
		int code = conn.getResponseCode();
		if (code == 200) {
			// 服务器返回的数据的长度 实际上就是文件的长度
			int length = conn.getContentLength();
			System.out.println("文件总长度:" + length);
			// 在客户端本地 创建出来一个大小跟服务器端文件一样大小的临时文件
			RandomAccessFile raf = new RandomAccessFile("setup.exe", "rwd");
			// 指定创建的这个文件的长度
			raf.setLength(length);
			raf.close();

			// 假设是3个线程去下载资源.
			// 平均每一个线程下载的文件的大小.
			int blockSize = length / threadCount;
			for (int threadId = 1; threadId <= threadCount; threadId++) {
				// 第一个线程下载的开始位置
				int startIndex = (threadId - 1) * blockSize;
				int endIndex = threadId * blockSize - 1;
				if (threadId == threadCount) {// 最后一个线程 下载的长度 要稍微长一点
					endIndex = length;
				}
				System.out.println("线程:" + threadId + "下载:---" + startIndex
						+ "--->" + endIndex);
				new DownloadThread(path, threadId, startIndex, endIndex)
						.start();
			}

		} else {
			System.out.println("服务器错误.");
		}
	}

	/**
	 * 下载文件的子线程 每一个线程 下载对应位置的文件
	 * 
	 * @author Administrator
	 * 
	 */
	public static class DownloadThread extends Thread {
		private int threadId;
		private int startIndex;
		private int endIndex;
		private String path;

		/**
		 * @param path
		 *            下载文件在服务器上的路径
		 * @param threadId
		 *            线程id
		 * @param startIndex
		 *            线程下载的开始位置
		 * @param endIndex
		 *            线程下载的结束位置.
		 */
		public DownloadThread(String path, int threadId, int startIndex,
				int endIndex) {
			this.threadId = threadId;
			this.startIndex = startIndex;
			this.endIndex = endIndex;
			this.path = path;
		}

		@Override
		public void run() {
			try {

				// 检查是否存在 记录下载长度的文件 ,如果存在读取这个文件的数据.
				File tempFile = new File(threadId + ".txt");
				if (tempFile.exists() && tempFile.length() > 0) {
					FileInputStream fis = new FileInputStream(tempFile);
					byte[] temp = new byte[1024];
					int leng = fis.read(temp);
					String downloadLen = new String(temp, 0, leng);
					int downloadlenInt = Integer.parseInt(downloadLen);
					startIndex = downloadlenInt;//修改下载的真实的开始位置.
					fis.close();
				}

				URL url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url
						.openConnection();
				conn.setRequestMethod("GET");
				// 重要: 请求服务器下载部分的文件 指定文件的位置.
				conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
						+ endIndex);
				System.out.println("线程真实下载:" + threadId + "下载:---" + startIndex
						+ "--->" + endIndex);
				conn.setConnectTimeout(5000);
				int code = conn.getResponseCode(); // 从服务器请求全部资源 200 ok
													// 如果从服务器请求部分资源 206 ok
				if (code == 206) {
					InputStream is = conn.getInputStream();// 已经设置了 请求的位置
					RandomAccessFile raf = new RandomAccessFile("setup.exe",
							"rwd");
					// 随机写文件的时候 从哪个位置开始写
					raf.seek(startIndex);// 定位文件
					int len = 0;
					byte[] buffer = new byte[1024];
					int total = 0;// 已经下载的数据长度
					while ((len = is.read(buffer)) != -1) {
						RandomAccessFile file = new RandomAccessFile(threadId
								+ ".txt", "rwd");// 作用: 记录当前线程下载的数据长度
						raf.write(buffer, 0, len);
						total += len;
						//System.out.println("线程:" + threadId + "total:" + total); 
						file.write(( total+startIndex+"").getBytes());//记录的是 下载位置.
						file.close();
					}
					is.close();
					raf.close();
					System.out.println("线程:" + threadId + "下载完毕了...");
				} else {
					System.out.println("线程:" + threadId + "下载失败...");
				}
				
				File deleteFile = new File(threadId+".txt");
				deleteFile.delete();//当线程下载完毕后 清楚掉 下载的记录
				
				//如何去判断应用程序已经下载完毕.
				
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				runningThread --;
				
				if(runningThread==0){//所有的线程 已经执行完毕了.
					for(int i= 1;i<=3;i++){
						File file = new File(i+".txt");
						file.delete();
					}
					System.out.println("文件下载完毕 ,删除所有的下载记录.");
				}
			}

		}
	}
RandomAccessFile raf = new RandomAccessFile("setup.exe","rwd");

这里的rwd是同步写入数据到磁盘。就是不缓存,直接写。

还有一个是rws。rws是将文件的元数据也同步写入磁盘。