断点下载

HttpURLConnection下载

 

1 正常下载

  下载数据,与获取服务器的响应正文没有什么不同,都是一些数据。但是,下载的文件可能不是文本,就不能在下载后在控制台打印出来了,而是应该创建一个文件,然后把获取到的响应数据保存到磁盘文件中。

 

// 创建URL对象,这个URL对应服务器上的一个AVI视频
		URL url = new URL("http://localhost/hello/resource/a.avi");
		// 获取连接对象
		HttpURLConnection httpCon = (HttpURLConnection)url.openConnection();
		// 设置请求方法为GET
		httpCon.setRequestMethod("GET");
		// 连接服务器
		httpCon.connect();
		
		// 获取服务器响应的状态码
		int code = httpCon.getResponseCode();
		// 如果响应成功
		if(code == 200) {
			// 获取连接的输入流对象
			InputStream in = new BufferedInputStream(httpCon.getInputStream());
			// 创建一个输出流对象,对应F:\\aa.avi文件,你应该知道,这会创建文件
			OutputStream out = new BufferedOutputStream(new FileOutputStream("F:\\aa.avi"));
			// 难道你不知道这是在干什么?
			byte[] buff = new byte[2048];
			int len;
			while((len = in.read(buff)) != -1) {
				out.write(buff, 0 , len);
			}
			out.close();
		}
		// 关闭连接
		httpCon.disconnect();

 

2 断点下载

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

需要告诉服务器,我要从资源的某个字节位置开始下载,而不是从头开始下载;

下载到的数据要追加到原来已下载文件的尾部,而不是创建新文件。

 

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

new FileOutputStream(a.txt, true);

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

 

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

httpCon.addRequestProperty(rangebytes=0-):表示从请求资源的0下标位置开始下载,直到资源结束;

httpCon.addRequestProperty(rangebytes=1024-):表示从请求资源的1024下标位置开始下载,直到资源结束;

httpCon.addRequestProperty(rangebytes=1024-2048):表示从请求资源的1024下标位置开始下载,直到资源的2048位置结束;

 

有了这个请求头,我们就可以通过请求头告诉服务器,从资源的哪个位置开始下载,而不是从头开始下载了。

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

File file = new File(F:\\aa.avi);

long length = file.length();

 

  还有一个问题需要注意,当使用了range头信息之后,就算响应成功了,但是返回的状态码也不会是200,而不是206

 

第一步:获取连接对象,设置GET请求

URL url = new URL("http://localhost/hello/resource/a.avi");
HttpURLConnection httpCon = (HttpURLConnection)url.openConnection();
httpCon.setRequestMethod("GET");

 第二步:获取已下载字节数,设置range请求头,连接服务器。

// 已下载字节数。默认已下载的字节数为0
		long alreadySize = 0;
		// 获取磁盘上的文件,把服务器上下载来的数据写入这个文件中!
		File file = new File("F:\\b.avi");
		// 判断文件是否存在,如果存在,说明原来下载过,不过可能没有下载完
		if(file.exists()) {
			// 如果文件存在,那么已下载的字节数就是文件的长度
			alreadySize = file.length();
		}
		// 添加range请求头,表示从alreadySize开始下载,到最后结束
		httpCon.addRequestProperty("range", "bytes=" + alreadySize + "-");
		httpCon.connect();

 

第三步:获取响应状态码,判断是否响应成功,如果响应成功,那么获取未下载的字节数,以及整个资源的字节个数。

 

<!--EndFragment-->

<!--EndFragment-->

<!--EndFragment-->

// 获取响应状态码
		int code = httpCon.getResponseCode();
		// 如果响应成功,因为使用了range请求头,那么响应成功的状态码为206,而不是200
		if(code == 206) {
			// 获取未下载的部分
			// 本方法用来获取响应正文的大小,但因为设置了range请求头,那么这个方法返回的就是剩余的大小
			long unfinishedSize = httpCon.getContentLength();
			// 计算总大小!已完成+未完成=整个资源的大小
			long size = alreadySize + unfinishedSize;

第四步:获取连接的输入流对象,创建输出流对象,让输出流对象绑定F:\b.avi文件。注意,一定设置为追加数据!

// 获取连接的输入流对象
InputStream in = new BufferedInputStream(httpCon.getInputStream());

// 创建输出流对象,目标为file

OutputStream out = new BufferedOutputStream(new FileOutputStream(file, true));

<!--EndFragment-->

 

第五步:开始下载,在下载过程中显示已下载的百分比!

byte[] buff = new byte[2048];
			int len;
			while((len = in.read(buff)) != -1) {
				out.write(buff, 0 , len);
				// 把每次下载的字节累加到已下载大小中
				alreadySize += len;
				// 用已下载大小和整个资源大小来计算下载的百分比
				System.out.printf("%.2f%%\n", alreadySize * 1.0 / size * 100);
				Thread.sleep(2);
			}
			out.close();			
			System.out.println("成功了!");
		} else {
			System.out.println("下载失败!");
		}
		httpCon.disconnect();

 

尝试下载一段时间后把程序结束,然后再运行程序!看看最终下载完成后文件是否可以使用!

<!--EndFragment-->

<!--EndFragment--> 

<!--EndFragment-->

猜你喜欢

转载自olikeit.iteye.com/blog/1847313
今日推荐