当前位置: 首页 > news >正文

Android 文件下载 FileDownloader

HttpURLConnection文件下载工具类

import android.util.Log;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Map;
import java.util.concurrent.Executors;/*** HttpURLConnection文件下载工具类*/
public class HttpFileDownloaderUtils {private static final String TAG = "HttpFileDownloaderUtils";// 默认缓冲区大小private static final int DEFAULT_BUFFER_SIZE = 8192;// 默认连接超时时间(毫秒)private static final int DEFAULT_CONNECT_TIMEOUT = 10000;// 默认读取超时时间(毫秒)private static final int DEFAULT_READ_TIMEOUT = 10000;private int bufferSize = DEFAULT_BUFFER_SIZE;private int connectTimeout = DEFAULT_CONNECT_TIMEOUT;private int readTimeout = DEFAULT_READ_TIMEOUT;private Map<String, String> requestHeaders;/*** 下载进度监听器*/public interface DownloadListener {/*** 下载进度更新* @param total 总大小(字节)* @param downloaded 已下载大小(字节)*/void onProgress(long total, long downloaded);/*** 下载完成* @param file 下载后的文件*/void onComplete(File file);/*** 下载失败* @param e 失败原因*/void onFailed(Exception e);}// 构造方法public HttpFileDownloaderUtils() {}public HttpFileDownloaderUtils(int connectTimeout, int readTimeout) {this.connectTimeout = connectTimeout;this.readTimeout = readTimeout;}// setter方法public void setBufferSize(int bufferSize) {this.bufferSize = bufferSize;}public void setConnectTimeout(int connectTimeout) {this.connectTimeout = connectTimeout;}public void setReadTimeout(int readTimeout) {this.readTimeout = readTimeout;}public void setRequestHeaders(Map<String, String> headers) {this.requestHeaders = headers;}/*** 下载文件(同步方法,可指定文件名)* @param fileUrl 文件URL* @param saveDir 保存目录* @param fileName 保存的文件名,为null则自动获取* @param listener 进度监听器* @return 下载的文件* @throws IOException 异常*/public File download(String fileUrl, String saveDir, String fileName, DownloadListener listener) throws IOException {// 验证参数if (fileUrl == null || fileUrl.isEmpty()) {Log.e(TAG, "文件URL不能为空");}if (saveDir == null || saveDir.isEmpty()) {Log.e(TAG, "保存目录不能为空");}// 创建保存目录File dir = new File(saveDir);if (!dir.exists() && !dir.mkdirs()) {Log.e(TAG, "无法创建保存目录: " + saveDir);}URL url = new URL(fileUrl);HttpURLConnection connection = (HttpURLConnection) url.openConnection();try {// 设置连接参数connection.setConnectTimeout(connectTimeout);connection.setReadTimeout(readTimeout);connection.setRequestMethod("GET");connection.setDoInput(true);// 设置请求头if (requestHeaders != null && !requestHeaders.isEmpty()) {for (Map.Entry<String, String> entry : requestHeaders.entrySet()) {connection.setRequestProperty(entry.getKey(), entry.getValue());}}// 连接connection.connect();// 检查响应码int responseCode = connection.getResponseCode();if (responseCode != HttpURLConnection.HTTP_OK) {Log.e(TAG, "HTTP响应错误: " + responseCode + " " + connection.getResponseMessage());}// 获取文件信息long contentLength = connection.getContentLengthLong();String finalFileName = fileName;// 如果未指定文件名,则自动获取if (finalFileName == null || finalFileName.isEmpty()) {finalFileName = getFileNameFromConnection(connection, fileUrl);}// 构建保存路径String saveFilePath = saveDir + File.separator + finalFileName;// 下载文件try (InputStream in = connection.getInputStream();FileOutputStream out = new FileOutputStream(saveFilePath)) {byte[] buffer = new byte[bufferSize];int bytesRead;long totalRead = 0;while ((bytesRead = in.read(buffer)) != -1) {out.write(buffer, 0, bytesRead);totalRead += bytesRead;// 通知进度if (listener != null) {listener.onProgress(contentLength, totalRead);}}}File downloadedFile = new File(saveFilePath);// 通知完成if (listener != null) {listener.onComplete(downloadedFile);}return downloadedFile;} finally {connection.disconnect();}}/*** 异步下载文件* @param fileUrl 文件URL* @param saveDir 保存目录* @param listener 进度监听器*/public void downloadAsync(String fileUrl, String saveDir, String saveName, DownloadListener listener) {Executors.newSingleThreadExecutor().execute(() -> {try {download(fileUrl, saveDir, saveName, listener);} catch (Exception e) {if (listener != null) {listener.onFailed(e);}}});}/*** 从连接中获取文件名*/private String getFileNameFromConnection(URLConnection connection, String fileUrl) {// 尝试从Content-Disposition头获取String disposition = connection.getHeaderField("Content-Disposition");if (disposition != null && disposition.contains("filename=")) {String fileName = disposition.substring(disposition.indexOf("filename=") + 9);// 处理可能包含的引号if (fileName.startsWith("\"") && fileName.endsWith("\"")) {fileName = fileName.substring(1, fileName.length() - 1);}return fileName;}// 从URL中获取文件名String fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1);// 处理URL参数int paramIndex = fileName.indexOf("?");if (paramIndex != -1) {fileName = fileName.substring(0, paramIndex);}return fileName;}
}

OkFileDownloadUtils

import android.content.Context;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;/*** Describe : okhttp下载文件*/
public class OkFileDownloadUtils {private static final String TAG = "DownloadUtil";private final OkHttpClient okHttpClient;private OkFileDownloadUtils() {okHttpClient = new OkHttpClient();}private static final class DownloadUtilsHolder {private static final OkFileDownloadUtils DOWNLOAD_UTILS = new OkFileDownloadUtils();}public static OkFileDownloadUtils getInstance() {return DownloadUtilsHolder.DOWNLOAD_UTILS;}public String destFileDir() {Context context = ApplicationManager.get();return context.getFilesDir().getAbsolutePath() + "/config";}/*** 下载文件** @param url          下载连接* @param destFileDir  下载的文件储存目录* @param destFileName 下载文件名称* @param listener     下载监听*/public void download(String url, String destFileDir, String destFileName, OnDownloadListener listener) {Request request = new Request.Builder().url(url).build();okHttpClient.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {// 下载失败监听回调listener.onDownloadFailed(e);e.printStackTrace();}@Overridepublic void onResponse(Call call, Response response) {byte[] buf = new byte[2048];int len = 0;File dir = new File(destFileDir);if (!dir.exists()) {dir.mkdirs();}File file = new File(dir, destFileName);ResponseBody body = response.body();if (body == null) {Log.e(TAG, "ResponseBody is null");return;}long total = body.contentLength();Log.e(TAG, "download onResponse total = " + total);try (InputStream is = body.byteStream();FileOutputStream fos = new FileOutputStream(file)) {long sum = 0;while ((len = is.read(buf)) != -1) {fos.write(buf, 0, len);sum += len;if(total > 0) {int progress = BigDecimal.valueOf(sum).divide(BigDecimal.valueOf(total), 2, RoundingMode.UP).multiply(BigDecimal.valueOf(100)).intValue();//下载中更新进度条listener.onDownloading(progress);}}fos.flush();//下载完成listener.onDownloadSuccess(file);} catch (IOException e) {listener.onDownloadFailed(e);e.printStackTrace();}}});}public interface OnDownloadListener {/*** 下载成功之后的文件*/void onDownloadSuccess(File file);/*** 下载进度*/void onDownloading(int progress);/*** 下载异常信息*/void onDownloadFailed(Exception e);}
}

http://www.dtcms.com/a/362041.html

相关文章:

  • TypeScript交叉类型、重复属性、类型断言和as const详解
  • 光颉科技)Viking)的CS25FTFR009 1225 0.009R/9mR 3W电阻介绍-华年商城
  • 【笔记】float类型的精度有限,无法精确表示123456.6789
  • 【Audio】静音或振动模式下重复来电响铃
  • Java Web项目后台管理系统之内容管理仿写(三):图片上传
  • 使用 BayesFlow 通过神经网络简化贝叶斯推断(一)
  • C扩展4:X宏(X-MACRO)
  • JS循环机制
  • IS-IS的原理
  • Java超卖问题
  • MySQL安装与使用指南
  • 【读论文】量子关联增强双梳光谱技术
  • 力扣404 代码随想录Day15 第三题
  • 故障排查指南:理解与解决 “No route to host“ 错误
  • NOSQL——Redis
  • MySQL基础知识保姆级教程(四)视图与约束
  • 浅谈中断控制器:从 IRQ 到 IRR、IMR、In-Service Register
  • 软考-操作系统-错题收集(3)文件系统的索引节点结构
  • 【前端】《手把手带你入门前端》前端的一整套从开发到打包流程, 这篇文章都会教会你;什么是vue,Ajax,Nginx,前端三大件?
  • ComPE for win 纯净的PE系统
  • 软考中级数据库系统工程师学习专篇(67、数据库恢复)
  • Spring Security 深度学习(四): 会话管理与CSRF防护
  • 2025 数字化转型期,值得关注的 10 项高价值证书解析
  • Linux笔记---计算机网络概述
  • 视频动作识别模型-C3D
  • 线程池项目代码细节5(解决linux死锁问题)
  • 关系型数据库——GaussDB的简单学习
  • 《投资-43》- 自然=》生物=》人类社会=》商业=》金融=》股市=》投资的共同逻辑:生存竞争与进化论
  • 前端实现查询数据【导出】功能
  • 自制扫地机器人(二) Arduino 机器人避障设计——东方仙盟