网络编程--多线程断点下载文件

今天学习了使用RandomAccessFile类实现多线程的下载。实现代码如下:

ThreadDownLoad.java

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
public class ThreadDownLoad {
	//定义线程的个数
	public static final int Thread_COunt = 3;
	static String path = "http://192.168.1.105:8080/2.docx";
 public static void main(String[] args) {
	//1、请求服务器,
	 URL url;
	try {
		url = new URL(path);
		HttpURLConnection conn = (HttpURLConnection)url.openConnection();
		conn.setReadTimeout(5000);
		if(conn.getResponseCode() == 200){
			//获取文件的大小
			int totalSize = conn.getContentLength();
			String fileName = getFileName(path);
			System.out.println(fileName+"-------");
			RandomAccessFile raf = new RandomAccessFile("F://fileUpload//"+getFileName(path), "rw");
			System.out.println("文件大小:"+totalSize);
			//为文件设置指定大小
			raf.setLength(totalSize);
			//定义平均没法线程需要下载的大小
			int blockSize = totalSize / Thread_COunt;
			//定义每个线程开始位置和结束位置
			int startSize = 0;
			int endSize = 0;
			for(int threadId = 0;threadId<Thread_COunt;threadId++){
				startSize = threadId * blockSize;
				endSize = (threadId+1)*blockSize-1;
				//如果文件不能平均分,那么线程3将下载所有剩余的内容。
				if(threadId == Thread_COunt-1 && totalSize % Thread_COunt!=0){
					endSize = totalSize -1;
				}
				new Downloader(threadId, startSize, endSize).start();
			}
		}
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	
}
 public static String getFileName(String path){
	 int num = path.lastIndexOf("/")+1;
	 return path.substring(num);
 }
 static class Downloader extends Thread{
	 //多线程下载,要获取startId、endId、threadId
	 private int threadId;
	 private int endId;
	 private int startId;
	 private int currentId;
	 public Downloader(int threadId,int startId,int endId){
		 this.endId = endId;
		 this.startId = startId;
		 this.threadId = threadId;
		 this.currentId = startId;
	 }
	 @Override
	public void run() {
		//在run方法中执行下载任务
		try {
			File tempFile = new File("F://fileUpload//"+threadId+".position");
			//当再次读取文件的时候,先判断临时文件是否存在。
			if(tempFile.exists()&&tempFile.length()>0){
				//如果存在,重新给给startId进行赋值。
				BufferedReader bis = new BufferedReader
						(new InputStreamReader(new FileInputStream(tempFile)));
				currentId = Integer.parseInt(bis.readLine());
				System.out.println("线程:"+threadId+"文件再次读取时的开始位置--"+currentId);
			}
			URL url = new URL(path);
			System.out.println("线程:"+threadId+"--开始位置currentId----"+currentId);
			HttpURLConnection conn = (HttpURLConnection)url.openConnection();
			conn.setRequestProperty("Range", "bytes:"+currentId+"-"+endId);
			int code  =  conn.getResponseCode();
			RandomAccessFile raf = new RandomAccessFile("F://fileUpload//"+getFileName(path), "rw");
			raf.seek(currentId);
			//获取服务器中的部分内容
			//为了实现每个线程下载东西都有固定的位置,所以必须告诉服务器,每个线程从什么位置下载到什么位置
			if(code == 206){  
				InputStream is = conn.getInputStream();
				//设置每个线程读取文件的开始位置
				byte[] b = new byte[1024*1024];
				int len =0;
				while((len = is.read(b))!=-1){
					raf.write(b, 0, len);
					currentId += len;  //获取每次循环读取的结束值
					//定义一个输出流
					//rws" 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。 
					RandomAccessFile fos = new RandomAccessFile(tempFile, "rws");
					System.out.println("线程:"+threadId+"当前写入文件的数据currentId==="+currentId);
					fos.write((currentId+"").getBytes());
					fos.close();
					sleep(300);
				}
			}
			raf.close();
			//循环完毕之后删除临时文件
			if(tempFile.exists()&&tempFile.length()>0){
				System.out.println("文件名:"+tempFile.getName());
				boolean flag= tempFile.delete();
				System.out.println("线程"+threadId+"删除成功?"+tempFile.delete());
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
 }
 
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值