【Android】安卓 Java下载ZIP文件并解压(笔记)

news/2025/3/20 21:46:50/

写在前面的话

在这篇文章中,我们将详细讲解如何在 Android 中通过 Java 下载 ZIP 文件并解压,同时处理下载进度、错误处理以及优化方案。


以下正文


1.权限配置

在 AndroidManifest.xml 中,我们需要添加相应的权限来确保应用能够访问网络和设备存储。

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

⚠️ 注意:Android 10(API 29)及以上,建议使用 getExternalFilesDir() 来处理文件,而避免直接访问 /sdcard。

2.下载 ZIP 文件并保存到本地

文件下载

首先,我们需要编写下载 ZIP 文件的代码。这里使用 HttpURLConnection 来实现文件的下载,并保存到设备的存储中。

java">public void downloadZipFile(String urlStr, String savePath, DownloadCallback callback) {new Thread(() -> {InputStream input = null;FileOutputStream output = null;HttpURLConnection connection = null;try {URL url = new URL(urlStr);connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(10000);connection.setReadTimeout(10000);connection.connect();if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {callback.onFailed("Server returned HTTP " + connection.getResponseCode());return;}int fileLength = connection.getContentLength();input = connection.getInputStream();File file = new File(savePath);output = new FileOutputStream(file);byte[] buffer = new byte[4096];int bytesRead;long total = 0;while ((bytesRead = input.read(buffer)) != -1) {total += bytesRead;output.write(buffer, 0, bytesRead);int progress = (int) (total * 100 / fileLength);callback.onProgress(progress);}callback.onSuccess(file.getAbsolutePath());} catch (Exception e) {e.printStackTrace();callback.onFailed(e.getMessage());} finally {try {if (output != null) output.close();if (input != null) input.close();} catch (IOException ignored) {}if (connection != null) connection.disconnect();}}).start();
}

下载回调

为了处理下载过程中的进度、成功与失败,我们需要定义一个回调接口:

java">public interface DownloadCallback {void onProgress(int progress);  // 下载进度void onSuccess(String filePath); // 下载完成void onFailed(String error);     // 下载失败
}

3.解压 ZIP 文件’

文件解压

下载完成后,我们可以解压 ZIP 文件。Android 提供了 ZipInputStream 来处理解压工作。以下是解压代码实现:

java">public void unzip(String zipFilePath, String targetDirectory, UnzipCallback callback) {new Thread(() -> {try {File destDir = new File(targetDirectory);if (!destDir.exists()) {destDir.mkdirs();}ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFilePath));ZipEntry zipEntry;byte[] buffer = new byte[1024];while ((zipEntry = zis.getNextEntry()) != null) {File newFile = new File(destDir, zipEntry.getName());if (zipEntry.isDirectory()) {newFile.mkdirs();} else {// 确保父目录存在new File(newFile.getParent()).mkdirs();FileOutputStream fos = new FileOutputStream(newFile);int len;while ((len = zis.read(buffer)) > 0) {fos.write(buffer, 0, len);}fos.close();}zis.closeEntry();}zis.close();callback.onSuccess(targetDirectory);} catch (IOException e) {e.printStackTrace();callback.onFailed(e.getMessage());}}).start();
}

解压回调

为了处理解压过程中的状态,我们也需要一个回调接口:

java">public interface UnzipCallback {void onSuccess(String targetPath);  // 解压成功void onFailed(String error);        // 解压失败
}

4.断点续传

对于较大的文件下载,可能需要实现断点续传功能。为了实现这一点,我们可以在下载时存储已下载的字节数,并在中断后继续下载。

修改 downloadZipFile 方法,使用 Range 头来支持断点续传:

java">public void downloadZipFileWithResume(String urlStr, String savePath, DownloadCallback callback) {new Thread(() -> {InputStream input = null;FileOutputStream output = null;HttpURLConnection connection = null;try {File file = new File(savePath);long downloadedLength = file.exists() ? file.length() : 0;URL url = new URL(urlStr);connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(10000);connection.setReadTimeout(10000);connection.setRequestProperty("Range", "bytes=" + downloadedLength + "-");connection.connect();if (connection.getResponseCode() != HttpURLConnection.HTTP_PARTIAL &&connection.getResponseCode() != HttpURLConnection.HTTP_OK) {callback.onFailed("Server returned HTTP " + connection.getResponseCode());return;}int fileLength = connection.getContentLength() + (int) downloadedLength;input = connection.getInputStream();output = new FileOutputStream(file, true);  // 以追加方式写入byte[] buffer = new byte[4096];int bytesRead;long total = downloadedLength;while ((bytesRead = input.read(buffer)) != -1) {total += bytesRead;output.write(buffer, 0, bytesRead);int progress = (int) (total * 100 / fileLength);callback.onProgress(progress);}callback.onSuccess(file.getAbsolutePath());} catch (Exception e) {e.printStackTrace();callback.onFailed(e.getMessage());} finally {try {if (output != null) output.close();if (input != null) input.close();} catch (IOException ignored) {}if (connection != null) connection.disconnect();}}).start();
}

5.调用示例

以下是如何使用我们实现的功能来下载、解压并处理回调:

java">// 下载地址和存储路径
String zipUrl = "https://example.com/path/to/file.zip";
File downloadDir = context.getExternalFilesDir(null); // 应用私有目录
String zipFilePath = new File(downloadDir, "downloaded_file.zip").getAbsolutePath();
String unzipTargetDir = new File(downloadDir, "unzipped_folder").getAbsolutePath();// 下载 ZIP 文件
downloadZipFile(zipUrl, zipFilePath, new DownloadCallback() {@Overridepublic void onProgress(int progress) {Log.d("Download", "Progress: " + progress + "%");}@Overridepublic void onSuccess(String filePath) {Log.d("Download", "Download completed: " + filePath);// 解压 ZIP 文件unzip(filePath, unzipTargetDir, new UnzipCallback() {@Overridepublic void onSuccess(String targetPath) {Log.d("Unzip", "Unzip completed at: " + targetPath);}@Overridepublic void onFailed(String error) {Log.e("Unzip", "Unzip failed: " + error);}});}@Overridepublic void onFailed(String error) {Log.e("Download", "Download failed: " + error);}
});

6.常见问题与优化建议

在实际开发中,下载和解压 ZIP 文件的过程中会遇到一些常见的问题。以下是一些优化建议和处理方法:

网络连接中断

在进行大文件下载时,网络连接可能会中断,导致下载失败。为了避免重复下载,建议使用断点续传技术。断点续传技术通过记录文件下载的进度,从而在网络中断后可以从中断位置继续下载,而不是重新开始。

优化建议:

  • 使用 Range 请求头来实现文件下载的断点续传(如上文所示)。
  • 在网络中断时,将已经下载的字节数保存在本地文件中,以便恢复下载。

文件解压失败

在解压 ZIP 文件时,如果文件结构复杂或者出现损坏,可能会导致解压失败。确保文件完整性是防止解压失败的关键。

优化建议:

  • 在解压前,可以验证 ZIP 文件的完整性,确保下载完成且未损坏。
  • 使用 ZipFile 类可以简化一些 ZIP 文件的解压操作,并能更好地处理压缩包中的特殊情况(如加密压缩包)。

性能优化

  • 缓冲区大小:在下载和解压文件时,使用适当大小的缓冲区(例如 4096 字节)可以提升性能。
  • UI 线程阻塞:确保所有的网络和解压操作都在后台线程中执行,避免阻塞 UI 线程,导致应用无响应。

文件存储权限问题

在 Android 10 及以上版本,Google 对外部存储的访问权限做出了更严格的限制。你需要使用 getExternalFilesDir() 方法来存储文件,这个目录是私有的,仅限应用本身访问,且不会在卸载应用时删除。

优化建议:

  • 使用 getExternalFilesDir() 或 MediaStore 来确保兼容性。
  • 针对 Android 11 及以上版本,需申请 MANAGE_EXTERNAL_STORAGE 权限以便访问共享存储。

文件大小限制

大文件的下载和解压会占用大量存储空间,尤其是当设备存储较满时,可能会导致下载失败或存储不足的问题。

优化建议:

  • 在下载前,检查设备存储空间是否足够,并提示用户进行清理。
  • 如果需要处理大文件,考虑在下载过程中显示文件大小,并在下载完成前通过 onProgress 更新下载进度。

http://www.ppmy.cn/news/1580690.html

相关文章

Docker基础知识介绍

Docker基础篇 必须要在Linux环境下才能运行&#xff0c;windows下运行也是安装虚拟机后才能下载安装运行 下载安装 linux 依次执行下边步骤 更新 yum yum update 卸载旧的Docker yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \do…

计算机网络笔记再战——理解几个经典的协议HTTP章3

理解几个经典协议——HTTP章3 返回结果的HTTP状态码 ​ 我们知道&#xff0c;ICMP可以传递IP通信时候的状态如何。HTTP虽然没有辅助的解析&#xff0c;但是它可以使用状态码来表达我们的HTTP请求的结果&#xff0c;标记服务器端的处理是否正常、通知出现的错误等工作。这就是…

Python 生成数据(随机漫步)

数据可视化 指的是通过可视化表示来探索数据&#xff0c;它与数据挖掘 紧密相关&#xff0c;而数据挖掘指的是使用代码来探索数据集的规律和关联。数据集可以是用一行代码就能表 示的小型数字列表&#xff0c;也可以是数以吉字节的数据。 随机漫步 在本节中&#xff0c;我们将…

POI和EasyExcel---处理Excel

01 Apache POI简介 Apache POI 是一个开源的Java库&#xff0c;用于处理Microsoft Office格式的文档。它提供了丰富的API&#xff0c;允许开发者在Java应用中读取、写入和操作Excel、Word、PowerPoint等文件&#xff0c;是处理Office文档的常用工具。 核心功能 • 支持多种格…

BFS,DFS带图详解+蓝桥杯算法题+经典例题

1.BFS和DFS的定义与实现方式 1.1 深度优先搜索&#xff08;DFS&#xff09; 基本概念&#xff1a;DFS 是一种用于遍历或搜索图或树的算法。它从起始节点开始&#xff0c;沿着一条路径尽可能深地探索下去&#xff0c;直到无法继续或者达到目标节点&#xff0c;然后回溯到上一个…

pytest 框架学习总结

视频&#xff1a;pytest01-快速上手_哔哩哔哩_bilibili 资料&#xff1a;pytest 框架 - 白月黑羽 基于 Python 语言的自动化测试框架 最知名的 有如下 3 款unittest、pytest、robotframework 前两款框架主要&#xff08;或者说很大程度上&#xff09;是 聚焦 在 白盒单元测试…

【图像处理基石】什么是HDR图片?

1. 什么是HDR图片&#xff1f; HDR&#xff08;高动态范围图像&#xff0c;High Dynamic Range&#xff09;是一种通过技术手段扩展照片明暗细节的成像方式。以下是关于HDR的详细说明&#xff1a; 核心原理 动态范围&#xff1a;指图像中最亮和最暗区域之间的亮度差。人眼能…

举例说明 牛顿法 Hessian 矩阵

矩阵求逆的方法及示例 目录 矩阵求逆的方法及示例1. 伴随矩阵法2. 初等行变换法矩阵逆的实际意义1. 求解线性方程组2. 线性变换的逆操作3. 数据分析和机器学习4. 优化问题牛顿法原理解释举例说明 牛顿法 Hessian 矩阵1. 伴随矩阵法 原理:对于一个 n n n 阶方阵 A A