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);}
}