HttpURLConnection 断点下载

什么叫断点下载?迅雷就可以断点下载!就是说下载了一半,然后把下载中断,明天打开电脑再继续下载。如果我在下载一个文件,先下载了50%,然后停止下载,然后再继续下载省下的50%。这里有两个问题需要我们处理:

  •  需要告诉服务器,我要从资源的某个字节位置开始下载,而不是从头开始下载;
  • 下载到的数据要追加到原来已下载文件的尾部,而不是创建新文件。

  第一个问题我们应该知道怎么处理,我们在学习IO流时应该知道FileOutputStream类的构造器可以接受一人boolean类型的参数:

newFileOutputStream(“a.txt”, true);

这表示如果a.txt文件不存在,那么创建它;如果a.txt文件存在,那么就把写入到流中的数据追加到a.txt文件的尾部。

 

第二个问题是需要通过请求头信息来处理,有一个请求头叫range:

  Range头域可以请求实体的一个或者多个子范围。

                   例如,  表示头500个字节:bytes=0-499   

                                 表示第二个500字节:bytes=500-999   

                                 表示最后500个字节:bytes=-500   

                                 表示500字节以后的范围:bytes=500-   

                                 第一个和最后一个字节:bytes=0-0,-1   

                                 同时指定几个范围:bytes=500-600,601-999   

         但是服务器可以忽略此请求头,如果无条件GET包含Range请求头,响应会以状态码206(PartialContent)返回而不是以200 (OK)。有了这个请求头,我们就可以通过请求头告诉服务器,从资源的哪个位置开始下载,而不是从头开始下载了。

但是,我们上一次下载了多少呢?我们需要告诉服务器从上一次下载的位置开始下载,但我们怎么知道上一次下载了多少呢?其实很简单就知道了,你下载的数据都写到目标文件中了,也就是那个还没有下载完的文件,一半的文件,你看看它的长度不就知道了么!

File file = new File(path);
long length = file.length();

2,具体代码实现:

/**
	 * 断点下载
	 * @throws InterruptedException 
	 */
	@Test public void testDebugDownload() throws IOException, InterruptedException{
		//创建URL对象
		URL url = new URL("http://localhost:8080/****/resource/kiss.avi");
		//使用url获取HttpURLConnection对象
		HttpURLConnection conn = (HttpURLConnection)url.openConnection();
		//客户端的请求方式
		conn.setRequestMethod("GET");
		//已经下载的字节数
		long alreadySize = 0;
		//将文件写到d:\kiss.avi中
		File file = new File("d:\\kiss.avi");
		//如果存在,说明原来下载过,不过可能没有下载完
		if(file.exists()){
			//如果文件存在,就获取当前文件的大小
			alreadySize = file.length();
		}
		/**
		 * Range头域可以请求实体的一个或者多个子范围。
		 * 		例如:	表示头500个字节:bytes=0-499   
		 *	    	 	表示第二个500字节:bytes=500-999   
		 *     		 	表示最后500个字节:bytes=-500   
		 *	     	 	表示500字节以后的范围:bytes=500-   
		 *	     	 	第一个和最后一个字节:bytes=0-0,-1   
		 *           	同时指定几个范围:bytes=500-600,601-999   
	     * 但是服务器可以忽略此请求头,如果无条件GET包含Range请求头,响应会以状态码206(PartialContent)返回而不是以200 (OK)。	
		 */
		conn.addRequestProperty("range", "bytes=" + alreadySize + "-");
		conn.connect();
		
		//206,一般表示断点续传
		//获取服务器回馈的状态码
		int code = conn.getResponseCode();
		// 如果响应成功,因为使用了range请求头,那么响应成功的状态码为206,而不是200
		if(code == 206){
			//获取未下载的文件的大小
			// 本方法用来获取响应正文的大小,但因为设置了range请求头,那么这个方法返回的就是剩余的大小
			long unfinishedSize = conn.getContentLength();
			//文件的大小
			long size = alreadySize + unfinishedSize;
			
			//获取输入流
			InputStream in = conn.getInputStream();
			//获取输出对象,参数一:目标文件,参数2表示在原来的文件中追加
			OutputStream out = new BufferedOutputStream(new FileOutputStream(file,true));
			
			//开始下载
			byte[] buff = new byte[2048];
			int len;
			StringBuilder sb = new StringBuilder();
			while((len = in.read(buff)) != -1){
				out.write(buff, 0, len);
				//将下载的累加到alreadSize中
				alreadySize += len;
				//下载进度
				System.out.printf("%.2f%%\n", alreadySize * 1.0 / size * 100);
				//由于文件大小可以看得到,那么我们这里使用阻塞
				Thread.sleep(2);
			}
			out.close();
			System.out.println("下载完成!!!");
		}else{
			System.out.println("下载失败!!!");
		}
		
		//断开连接
		conn.disconnect();
	}



  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值