import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

public class FileDown {
/**
* 说明:根据指定URL将文件下载到指定目标位置
*
* @param urlPath
* 下载路径
* @param downloadDir
* 文件存放目录
* @return 返回下载文件
*/
@SuppressWarnings("finally")
public static File downloadFile(String urlPath, String downloadDir) {
File file = null;
try {
// 统一资源
URL url = new URL(urlPath);
// 连接类的父类,抽象类
URLConnection urlConnection = url.openConnection();
// http的连接类
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
//设置超时
httpURLConnection.setConnectTimeout(1000*5);
//设置请求方式,默认是GET
httpURLConnection.setRequestMethod("GET");
// 设置字符编码
httpURLConnection.setRequestProperty("Charset", "UTF-8");
// 打开到此 URL引用的资源的通信链接(如果尚未建立这样的连接)。
httpURLConnection.connect();
// 文件大小
int fileLength = httpURLConnection.getContentLength();

// 控制台打印文件大小
System.out.println("您要下载的文件大小为:" + fileLength / (1024 * 1024) + "MB");

// 建立链接从请求中获取数据
URLConnection con = url.openConnection();
BufferedInputStream bin = new BufferedInputStream(httpURLConnection.getInputStream());
// 指定文件名称(有需求可以自定义)
String fileFullName = "aaa.apk";
// 指定存放位置(有需求可以自定义)
String path = downloadDir + File.separatorChar + fileFullName;
file = new File(path);
// 校验文件夹目录是否存在,不存在就创建一个目录
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}

OutputStream out = new FileOutputStream(file);
int size = 0;
int len = 0;
byte[] buf = new byte[2048];
while ((size = bin.read(buf)) != -1) {
len += size;
out.write(buf, 0, size);
// 控制台打印文件下载的百分比情况
System.out.println("下载了-------> " + len * 100 / fileLength + "%\n");
}
// 关闭资源
bin.close();
out.close();
System.out.println("文件下载成功!");
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("文件下载失败!");
} finally {
return file;
}

}

/**
* 测试
*
* @param args
*/
public static void main(String[] args) {
// 指定资源地址,下载文件测试
downloadFile("http://www.gov.cn/zhengce/pdfFile/1970_PDF.pdf", "d:/myPdf");

}
}

以上是转自https://blog.csdn.net/u010197393/article/details/80476512,不过我有个疑问
HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;为什么可以转呢,抽象类可以转成子类?我们学习java基础的时候不是说过抽象类URLConnection转成子类的前提是urlConnection的实例必须是子类,可以查看了openConnect()方法返回的是一个抽象类
是不是很奇怪?对这个问题我进行了源码深入.先从哪里看呢,根据 url.openConnection();我们先从URL开始看
1.第一步查看URL类,点击url.openConnection方法里面调用的是 
return handler.openConnection(this);
那么这个hander是什么东西呢?我们该类里面有一个叫做URLStreamHandler handler的声明,最终调用的还是hander.openConnection(),不过这个hander那么多子类继承方法(如下图),具体要调用哪个子类呢?

 

2.分析到这里,我们还是重点放在URL的构造方法上面

 public URL(String spec) throws MalformedURLException {
        this(null, spec);
    }

this方法最后会调用哪些代码呢?看图

 

看图可以说明,URL在初始化的时候应该就是根据我们初始化 URL url = new URL(urlPath);这个的时候判断是不是http,上图我打断点确实最后是http协议,然后hander会调用相应的子类,具体来说会调用sun.net.www.protocol.http的hander,是不是这样子呢?看下图就知道

 

3.最后一步看清楚了,其实在上图就可以看出,会调用上图最后一个方法,返回的是HttpURLConnection的实例,所以真相大白了,url.openConnection()是根据url来决定是哪个子类的,该例子中传了‘http://www.gov.cn/zhengce/pdfFile/1970_PDF.pdf’,最后返回的是HttpURLConnection的子类。

好了,是时候睡觉了


posted on 2019-07-23 18:13  我是坏男孩  阅读(303)  评论(0编辑  收藏  举报