Java下载大文件

一、需求:

根据Url下载大文件,创建本地文件,从输入流读取并写入文件,要求能满足大文件的下载,不能出现OOM

二、基于OKHttp
1.引入依赖
<!-- OK HTTP -->
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.12.0</version>
</dependency>
2.下载文件代码
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * 下载文件并保存
 * @param url 下载地址
 * @param folder 本地保存文件夹路径,比如:E:\test\down
 * @return 文件(下载失败返回null)
 */
public File downloadFile(String url, String folder){
    OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder().url(url).build();

    try(Response response = client.newCall(request).execute()){
    	//从Url提取文件名
	    String fileName = getFileNameFromUrl(url);
	    //拼接完整文件路径
	    String filePath = folder + File.separator + fileName;
        if(response.isSuccessful()){
            if(Objects.isNull(response.body())){
                logger.info("下载失败,响应体为空");
                return null;
            }
            //创建本地文件
            File file = new File(filePath);
            try(
                InputStream in = response.body().byteStream();//获取响应输入流
                FileOutputStream out = new FileOutputStream(file)//创建文件输出流
            ){
                //写入本地文件
                int len;
                byte[] buffer = new byte[4096];
                while((len = in.read(buffer)) != -1) { //从输入流中读取数据到缓冲区
                    out.write(buffer, 0, len); //将缓冲区的数据写入输出流
                }
                out.flush(); //刷新输出流缓冲区
            }
            return file;
        }else{
            logger.info("响应失败:httpStatus={}", response.code());
            return null;
        }
    }catch (Exception e){
        logger.info("文件下载失败,地址:{},错误:{}", url, e.getMessage(), e);
        return null;
    }
}
3.下载超时&https
OkHttpClient client = new OkHttpClient.Builder()
	 //如果下载超时,可以调整超时时间
	.readTimeout(16, TimeUnit.MINUTES)
	//下面两项配置可以解决https链接下载报错的问题(通过屏蔽SSL证书验证)
	.sslSocketFactory(IgnoreSSL.sslSocketFactory, IgnoreSSL.x509TrustManager)
	.hostnameVerifier(IgnoreSSL.hostnameVerifier)
	.build();
public class IgnoreSSL {
	public static final HostnameVerifier hostnameVerifier = (hostname, session) -> true;
    public static final SSLSocketFactory sslSocketFactory = sslContext().getSocketFactory();
    public static final X509TrustManager x509TrustManager = new X509TrustManager() {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) {}
        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) {}
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[] {};
        }
    };
    
    public static SSLContext sslContext(){
        try{
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, new TrustManager[] { x509TrustManager }, new SecureRandom());
            return sslContext;
        }catch (NoSuchAlgorithmException|KeyManagementException e) {
            throw new RuntimeException("SSL ignore error: "+e.getMessage(), e);
        }
    }
}
三、基于Hutool
1.引入依赖
<!-- Hutool工具包 -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.16</version>
</dependency>
2.下载文件代码
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;

/**
 * 下载文件并保存
 * @param url 下载地址
 * @param folder 本地保存文件夹路径,比如:E:\test\down
 * @return 文件(下载失败返回null)
 */
public File downloadFile(String url, String folder){
	//注意必须使用:executeAsync()
    try(HttpResponse response = HttpUtil.createGet(url).executeAsync()){
        //从Url提取文件名
        String fileName = getFileNameFromUrl(url);
        //拼接完整路径(含文件名)
        String filePath = folder+ File.separator +fileName;
        //响应处理
        if(response.isOk()){
            File file = new File(filePath);//创建本地文件
            try(
                InputStream in = response.bodyStream();//获取响应输入流
                FileOutputStream out = new FileOutputStream(file)//创建文件输出流
            ){
                //写入本地文件
                int len;
                byte[] buffer = new byte[4096];
                while((len = in.read(buffer)) != -1) { //从输入流中读取数据到缓冲区
                    out.write(buffer, 0, len); //将缓冲区的数据写入输出流
                }
                out.flush(); //刷新输出流缓冲区
            }
            return file;
        }else{
            logger.info("响应失败:httpStatus={}", response.getStatus());
            return null;
        }
    }catch (Exception e){
        logger.info("文件下载失败,地址:{},错误:{}", url, e.getMessage(), e);
        return null;
    }
}
四、辅助方法
import cn.hutool.core.net.URLDecoder;
import java.nio.charset.StandardCharsets;

/**
 * 从Url提取文件名
 * @param url 文件路径
 * @return 文件名
 */
private static String getFileNameFromUrl(String url){
    String uri = URLDecoder.decode(url.trim(), StandardCharsets.UTF_8);
    int index = uri.lastIndexOf("/");
    return  index==-1 ? uri : uri.substring(index+1);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在使用OkHttp进行多线程下载并更新App时,需要解决几个核心问题。首先,需要通过OkHttp获取远程Http资源的文件尺寸。可以使用OkHttpClient来设置连接超时时间和读取超时时间,并创建一个Request对象,然后使用Call的execute()方法来发送请求并获取Response对象。通过判断Response的状态码是否为200,可以获取到文件的尺寸。\[1\] 另外,为了实现可断点续传的功能,需要处理一些小技巧。当用户点击"STOP"按钮时,需要能够中断正在下载的进度。而当用户再次点击"DOWNLOAD"按钮时,各子线程需要能够继续之前的下载进度。为了实现这个功能,需要进行子线程和主线程之间的状态通信,以判断每个子线程的运行是否已经结束。\[2\] 在实现多线程下载更新App的过程中,可以继续使用OkHttp组件,并结合SQLite来存储下载时的实时进度。每次下载开始时,可以判断是覆盖式下载还是续传式下载。此外,可以对Android自带的进度条进行美化,以提升用户体验。这样的功能整合实验可以帮助实现一个基于多线程的可断点续传的下载器。\[3\] #### 引用[.reference_title] - *1* [Android入门第56天-在Android里使用OKHttp多线程下载文件并展示其进度](https://blog.csdn.net/lifetragedy/article/details/128520249)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Android入门第57天-使用OKHttp多线程制作像迅雷一样的断点续传功能](https://blog.csdn.net/lifetragedy/article/details/128591573)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值