栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

断点续传教学例子

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

断点续传教学例子

package net.url;
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.TimeUnit;
 

public class BreakpointResume {
	
	private static final long FRAGMENT_SIZE = 2048L;
	
	private static final String LOCAL_PATH = "D:\Demo";
 
	
	public static void main(String[] args) throws Exception {
		if (args.length != 1 && args.length != 2) {
			System.out.println("Usage[1]:java BreakpointResume url localFile");
			System.out.println("or Usage[2]:java BreakpointResume url");
			return;
		}
 
		String localFile = null;
		String url = args[0];
		if (args.length == 2) {
			localFile = args[1];
		}
		// 1. 校验URL和本地文件的格式
		String checkURLMsg = checkURLFormat(url);
		if (checkURLMsg != null) {
			System.err.println(checkURLMsg);
			return;
		}
		String checkLocalFileMsg = checkLocalFileFormat(localFile);
		if (checkLocalFileMsg != null) {
			System.err.println(checkLocalFileMsg);
			return;
		}
 
		// 2. 计算Range的范围
		long startRange, endRange;
		if (localFile == null) {
			startRange = 0L;
			endRange = FRAGMENT_SIZE;
		} else {
			startRange = new File(localFile).length();
			endRange = startRange + FRAGMENT_SIZE;
		}
		
		// 3. 访问网络资源然后分段下载
		downloadPartially(url, localFile, startRange, endRange);
	}
	
	
	private static void downloadPartially(String url, String localFile, long startRange, long endRange) throws MalformedURLException {
		long startTime = System.currentTimeMillis();
		URL resource = new URL(url);
		
		// 加入num是用来模拟Web资源传输了一部分,然后第二次传输时,从上次结束的部分开始获取
		int num = 0;
		while (true) {
			if (++num == 10) {
//				break;
			}
			HttpURLConnection conn = null;
			InputStream in = null;
			RandomAccessFile raf = null;
			try {
				conn = (HttpURLConnection) resource.openConnection();
				// 1) 设置请求属性Range
				conn.setRequestProperty("Range", "bytes=" + startRange + "-" + (endRange == -1L ? "" : endRange));
				// 2) 连接远程Web资源
				conn.connect();
				// 3) 校验状态行,如果不是成功或者部分内容,就停止传输
				String statusLine = conn.getHeaderField(null);// 状态行
				System.out.println("statusLine=" + statusLine);
				if (!statusLine.contains("200") && !statusLine.contains("206")) {
					throw new Exception("获取Web资源[" + url + "]时,响应状态不是200或者206");
				}
 
				// 获取资源长度
				String cr = conn.getHeaderField("Content-Range");
				if (cr == null || "".equals(cr.trim())) {
					throw new Exception("获取Web资源[" + url + "]时,响应信息中Content-Range为null");
				}
				System.out.println("Content-Range=" + cr);
				cr = cr.replace("[", "").replace("]", "").replace("bytes", "").trim();
				// 解析响应消息头中Content-Range字段的值
				long resourceStartPos = Long.parseLong(cr.substring(0, cr.indexOf("-")));
				long resourceEndPos = Long.parseLong(cr.substring(cr.indexOf("-") + 1, cr.indexOf("/")));
				long resourceTotalLength = Long.parseLong(cr.substring(cr.indexOf("/") + 1));
				System.out.println("resourceStartPos=" + resourceStartPos
						+ ", resourceEndPos=" + resourceEndPos
						+ ", resourceTotalLength=" + resourceTotalLength);
				// 将相应内容读取到buf中
				byte[] buf = new byte[(int) (resourceEndPos - resourceStartPos)];
				in = conn.getInputStream();
				in.read(buf);
				
				// 4) 查看.tmp文件是否已经存在,如果不存在,就新建该文件
				if (localFile == null) {
					localFile = LOCAL_PATH + File.separator + url.substring(url.lastIndexOf("/") + 1) + ".tmp";
				}
				System.out.println("localFile=" + localFile);
				File f = new File(localFile);
				if (!f.exists()) {// .tmp文件不存在,使用OutputStream手动创建该文件
					OutputStream os = new FileOutputStream(f);
					try {os.close();} catch (Exception e) {}
				}
				
				TimeUnit.MILLISECONDS.sleep(10L);
				raf = new RandomAccessFile(f, "rwd");
				raf.seek(startRange);
				raf.write(buf);
				try {raf.close();} catch (Exception e) {}
 
				// 5) 如果Web资源已经全部传输完了,将.tmp文件的后缀去掉,还原为文件本来的后缀和格式,然后结束while循环
				// 从Web服务器返回的内容中的字节,是以0为索引开始计数的
				if (resourceEndPos == resourceTotalLength - 1) {
					f.renameTo(new File(LOCAL_PATH + File.separator + url.substring(url.lastIndexOf("/") + 1)));
					break;
				}
				
				// 6) 如果Web资源没有传输完,计算下一次传输的Range的范围
				// 如果剩下的要传输的内容不超过FRAGMENT_SIZE的1.5倍,就一起全部传输过来,减少HttpURLConnection连接带来的资源消耗
				if (resourceTotalLength - resourceEndPos <= FRAGMENT_SIZE * 3 / 2) {
					startRange = resourceEndPos;
					endRange = -1L;
				} else {
					startRange = resourceEndPos;
					endRange = resourceEndPos + FRAGMENT_SIZE;
				}
				System.out.println("next startRange=" + startRange + ", endRange=" + endRange);
			} catch (Exception e) {
				System.err.println(e.getMessage());
				return;
			} finally {
				if (in != null) {
					try {in.close();} catch (Exception e) {}
				}
				if (conn != null) {
					conn.disconnect();
				}
			}
		}
		long time = System.currentTimeMillis() - startTime;
		System.out.println("传输Web资源[" + url + "]共耗时" + time / 1000 + "s" + time % 1000 + "ms");
	}
 
	
	private static String checkURLFormat(String url) {
		if (url.length() < 20) {
			return "url的长度至少为20";
		}
 
		String protocol = url.substring(0, 7);
		if (!protocol.equalsIgnoreCase("http://")) {
			return "url必须以http://开头(不区分大小写)";
		}
 
		int dotIndex = url.lastIndexOf(".");
		if (dotIndex == -1) {
			return "url中必须有'.'";
		}
 
		String resourceSuffix = url.substring(dotIndex);
		if (resourceSuffix.length() > 10) {
			return "url格式不正确,资源名称的后缀('.'后面的字符)不能超过10个字符";
		}
		return null;
	}
 
	
	private static String checkLocalFileFormat(String localFile) {
		if (localFile == null) {
			return null;
		}
 
		String retMsg = null;
		try {
			File f = new File(localFile);
			if (!f.exists()) {
				retMsg = "本地文件[" + localFile + "]不存在";
			} else if (!f.isFile()) {
				retMsg = "本地文件[" + localFile + "]不是一个文件";
			} else if (!localFile.endsWith(".tmp")) {
				retMsg = "本地文件[" + localFile + "]应该以.tmp结尾";
			}
		} catch (Exception e) {
			retMsg = "在读取本地文件[" + localFile + "]时出错,请检查该文件";
		}
		return retMsg;
	}
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/237847.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号