请作为资深开发工程师,解释我给出的代码。请逐行分析我的代码并给出你对这段代码的理解。
我给出的代码是:
【package com.isa.navi.jni.hmi;
import com.isa.navi.utils.LogUtils;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/**
* ZipUtils 类是一个工具类,用于处理 ZIP 文件的压缩和解压缩操作。
* 它采用了单例设计模式,确保整个应用程序中只有一个 ZipUtils 实例。
*/
public class ZipUtils {
/**
* 用于日志记录的标签。
*/
static private final String TAG = "UPDATE";
/**
* ZipUtils 类的单例实例。
* 使用 volatile 关键字确保多线程环境下的可见性和有序性。
*/
private volatile static ZipUtils mInstance;
/**
* 缓冲区大小
*/
private static final int BUFFER_SIZE = 10 * 1024 * 1024;
private long lastCheckTime;
/**
* 私有构造函数,防止外部类通过 `new` 关键字创建 ZipUtils 实例。
*/
private ZipUtils() {
}
/**
* 获取 ZipUtils 类的单例实例。
*
* @return ZipUtils 类的单例实例。
*/
public static ZipUtils getInstance() {
if (mInstance == null) {
synchronized (ZipUtils.class) {
if (mInstance == null) {
mInstance = new ZipUtils();
}
}
}
return mInstance;
}
public boolean unzip(String zipFilePath, String outputDir) {
boolean success = true; // 假设解压成功
File dir = new File(outputDir);
if (!dir.exists()) {
if (!dir.mkdirs()) { // 创建输出目录
LogUtils.e("无法创建输出目录: " + outputDir);
return false;
}
}
try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFilePath)))) {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
String entryName = entry.getName();
File outputFile = new File(outputDir, entryName);
// 创建子目录(如果需要)
File parentDir = outputFile.getParentFile();
if (parentDir != null && !parentDir.exists()) {
if (!parentDir.mkdirs()) {
LogUtils.e("无法创建子目录: " + parentDir.getAbsolutePath());
success = false; // 创建目录失败
continue; // 跳过当前条目
}
}
if (!entry.isDirectory()) {
// 解压文件内容
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outputFile))) {
byte[] buffer = new byte[BUFFER_SIZE]; // 缓冲区大小为 8KB
int bytesRead;
while ((bytesRead = zis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
// 优化后的检查逻辑(每秒最多1次)
long currentTime = System.currentTimeMillis();
if (currentTime - lastCheckTime > 1000) {
synchronized (this) {
if (currentTime - lastCheckTime > 1000) {
if (!HmiJNIImpl.getInstance().mapControl()) {
return false;
}
lastCheckTime = currentTime;
}
}
}
}
} catch (IOException e) {
LogUtils.e("写入文件失败: " + outputFile.getAbsolutePath() + " 错误: " + e.getMessage());
success = false; // 写入文件失败
}
} else {
// 创建空目录
if (!outputFile.mkdirs()) {
LogUtils.e("无法创建目录: " + outputFile.getAbsolutePath());
success = false; // 创建目录失败
}
}
zis.closeEntry(); // 关闭当前条目
}
} catch (IOException e) {
LogUtils.e("解压 ZIP 文件时发生错误: " + e.getMessage());
success = false; // 捕获到异常,解压失败
}
// 如果解压成功,则删除原始 ZIP 文件
if (success) {
File zipFile = new File(zipFilePath);
if (!zipFile.delete()) {
LogUtils.e("无法删除原始 ZIP 文件: " + zipFilePath);
success = false; // 如果删除失败,标记为失败
} else {
LogUtils.i("原始 ZIP 文件已成功删除: " + zipFilePath);
}
}
return success; // 返回最终结果
}
/**
* 压缩文件或目录到ZIP文件
*
* @param sourcePath 要压缩的文件或目录路径
* @param outputZipPath 输出的ZIP文件路径
* @param includeParent 是否包含父目录
* @return 压缩是否成功
*/
public boolean zip(String sourcePath, String outputZipPath, boolean includeParent) {
LogUtils.i(TAG, "sourcePath:" + sourcePath);
LogUtils.i(TAG, "outputZipPath:" + outputZipPath);
File sourceFile = new File(sourcePath);
if (!sourceFile.exists()) {
LogUtils.e(TAG, "源文件/目录不存在: " + sourcePath);
return false;
}
try (FileOutputStream fos = new FileOutputStream(outputZipPath);
BufferedOutputStream bos = new BufferedOutputStream(fos);
ZipOutputStream zos = new ZipOutputStream(bos)) {
// 设置压缩级别(可选)
zos.setLevel(Deflater.BEST_SPEED);
if (sourceFile.isDirectory()) {
// 压缩目录
if(!zipDirectory(sourceFile, sourceFile.getParentFile(), zos, includeParent)) {
return false;
}
} else {
// 压缩单个文件
if(!zipFile(sourceFile, sourceFile.getParentFile(), zos, includeParent)) {
return false;
}
}
LogUtils.i(TAG, "压缩完成: " + outputZipPath);
return true;
} catch (IOException e) {
LogUtils.e(TAG, "压缩过程中发生错误: " + e.getMessage());
return false;
}
}
/**
* 递归压缩目录
*
* @param directory 要压缩的目录
* @param baseDir 基础目录(用于计算相对路径)
* @param zos Zip输出流
* @param includeParent 是否包含父目录
* @throws IOException IO异常
*/
private boolean zipDirectory(File directory, File baseDir, ZipOutputStream zos, boolean includeParent)
throws IOException {
// 获取目录中的所有文件和子目录
File[] files = directory.listFiles();
if (files == null) return false;
// 如果目录不为空,添加目录条目(空目录也需要添加)
if (files.length > 0 || includeParent) {
String entryName = getRelativePath(directory, baseDir, includeParent) + "/";
ZipEntry dirEntry = new ZipEntry(entryName);
dirEntry.setTime(directory.lastModified());
zos.putNextEntry(dirEntry);
zos.closeEntry();
}
// 递归处理所有文件和子目录
for (File file : files) {
if (file.isDirectory()) {
if(!zipDirectory(file, baseDir, zos, includeParent)) {
return false;
}
} else {
if(!zipFile(file, baseDir, zos, includeParent)) {
return false;
}
}
}
return true;
}
/**
* 压缩单个文件
*
* @param file 要压缩的文件
* @param baseDir 基础目录(用于计算相对路径)
* @param zos Zip输出流
* @param includeParent 是否包含父目录
* @throws IOException IO异常
*/
private boolean zipFile(File file, File baseDir, ZipOutputStream zos, boolean includeParent)
throws IOException {
// 创建ZIP条目
String entryName = getRelativePath(file, baseDir, includeParent);
ZipEntry zipEntry = new ZipEntry(entryName);
zipEntry.setTime(file.lastModified());
zipEntry.setSize(file.length());
zos.putNextEntry(zipEntry);
// 写入文件内容
try (FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis)) {
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
zos.write(buffer, 0, bytesRead);
// 优化后的检查逻辑(每秒最多1次)
long currentTime = System.currentTimeMillis();
if (currentTime - lastCheckTime > 1000) {
synchronized (this) {
if (currentTime - lastCheckTime > 1000) {
if (!HmiJNIImpl.getInstance().mapControl()) {
return false;
}
lastCheckTime = currentTime;
}
}
}
}
}
zos.closeEntry();
return true;
}
/**
* 获取文件相对于基础目录的路径
*
* @param file 文件或目录
* @param baseDir 基础目录
* @param includeParent 是否包含父目录
* @return 相对路径
*/
private String getRelativePath(File file, File baseDir, boolean includeParent) {
Path filePath = file.toPath();
Path basePath = baseDir.toPath();
if (includeParent) {
// 包含父目录(压缩整个目录结构)
return basePath.relativize(filePath).toString().replace(File.separator, "/");
} else {
// 不包含父目录(只压缩内容)
Path parentPath = file.getParentFile().toPath();
return parentPath.relativize(filePath).toString().replace(File.separator, "/");
}
}
public String[] findEncryptedZipFiles(String directory) {
File dir = new File(directory);
String[] result = new String[2];;
if (!dir.exists() || !dir.isDirectory()) {
System.err.println("指定目录不存在或不是一个目录: " + directory);
return result;
}
File[] files = dir.listFiles();
if (files == null || files.length == 0) {
System.err.println("目录为空: " + directory);
return result;
}
for (File file : files) {
String fileName = file.getName();
if (fileName.endsWith(".zip.enc.sig")) {
result[0] = file.getAbsolutePath();
continue;
}
if (fileName.endsWith(".zip.enc")) {
result[1] = file.getAbsolutePath();
}
}
return result;
}
/**
* 压缩指定目录下的所有DB文件到ZIP包
*
* @param sourceDir 源目录路径
* @param outputZipPath 输出的ZIP文件路径
* @return 压缩是否成功
*/
public boolean zipDbFiles(String sourceDir, String outputZipPath) {
File dir = new File(sourceDir);
if (!dir.exists() || !dir.isDirectory()) {
LogUtils.e(TAG, "源目录不存在或不是目录: " + sourceDir);
return false;
}
// 查找所有.db文件
List<File> dbFiles = findFilesByExtension(dir, ".db");
if (dbFiles.isEmpty()) {
LogUtils.e(TAG, "未找到任何.db文件: " + sourceDir);
return false;
}
// 压缩文件
return zipFileList(dbFiles, dir, outputZipPath, false);
}
/**
* 压缩指定目录下的特定扩展名文件到ZIP包
*
* @param sourceDir 源目录路径
* @param outputZipPath 输出的ZIP文件路径
* @param extension 文件扩展名(如".db", ".txt")
* @return 压缩是否成功
*/
public boolean zipFilesByExtension(String sourceDir, String outputZipPath, String extension) {
File dir = new File(sourceDir);
if (!dir.exists() || !dir.isDirectory()) {
LogUtils.e(TAG, "源目录不存在或不是目录: " + sourceDir);
return false;
}
// 查找指定扩展名的文件
List<File> files = findFilesByExtension(dir, extension);
if (files.isEmpty()) {
LogUtils.e(TAG, "未找到任何" + extension + "文件: " + sourceDir);
return false;
}
return zipFileList(files, dir, outputZipPath, false);
}
/**
* 压缩文件列表到ZIP包
*
* @param files 要压缩的文件列表
* @param baseDir 基础目录(用于计算相对路径)
* @param outputZipPath 输出的ZIP文件路径
* @param preservePath 是否保留目录结构
* @return 压缩是否成功
*/
public boolean zipFileList(List<File> files, File baseDir, String outputZipPath, boolean preservePath) {
if (files == null || files.isEmpty()) {
LogUtils.e(TAG, "文件列表为空");
return false;
}
try (FileOutputStream fos = new FileOutputStream(outputZipPath);
BufferedOutputStream bos = new BufferedOutputStream(fos);
ZipOutputStream zos = new ZipOutputStream(bos)) {
zos.setLevel(Deflater.BEST_SPEED); // 设置压缩级别
for (File file : files) {
if (!file.exists() || file.isDirectory()) {
LogUtils.d(TAG, "跳过不存在的文件或目录: " + file.getAbsolutePath());
continue;
}
// 计算ZIP条目名称
String entryName = preservePath ?
getRelativePath(file, baseDir) :
file.getName();
// 添加文件到ZIP
if(!addFileToZip(file, entryName, zos)) {
return false;
}
}
LogUtils.i(TAG, "成功压缩 " + files.size() + " 个文件到: " + outputZipPath);
return true;
} catch (IOException e) {
LogUtils.e(TAG, "压缩文件列表时出错: " + e.getMessage());
return false;
}
}
/**
* 查找指定目录下特定扩展名的所有文件
*
* @param directory 要搜索的目录
* @param extension 文件扩展名(如".db")
* @return 匹配的文件列表
*/
private List<File> findFilesByExtension(File directory, String extension) {
List<File> result = new ArrayList<>();
if (directory == null || !directory.isDirectory()) {
return result;
}
File[] files = directory.listFiles();
if (files == null) {
return result;
}
// 确保扩展名以点开头
String normalizedExtension = extension.startsWith(".") ?
extension.toLowerCase() :
"." + extension.toLowerCase();
for (File file : files) {
if (file.isFile() && file.getName().toLowerCase().endsWith(normalizedExtension)) {
result.add(file);
}
}
return result;
}
/**
* 添加单个文件到ZIP输出流
*
* @param file 要添加的文件
* @param entryName ZIP条目名称
* @param zos ZIP输出流
*/
private boolean addFileToZip(File file, String entryName, ZipOutputStream zos) throws IOException {
ZipEntry zipEntry = new ZipEntry(entryName);
zipEntry.setTime(file.lastModified());
zipEntry.setSize(file.length());
zos.putNextEntry(zipEntry);
try (FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis)) {
byte[] buffer = new byte[1024 * 1024];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
zos.write(buffer, 0, bytesRead);
// 优化后的检查逻辑(每秒最多1次)
long currentTime = System.currentTimeMillis();
if (currentTime - lastCheckTime > 1000) {
synchronized (this) {
if (currentTime - lastCheckTime > 1000) {
if (!HmiJNIImpl.getInstance().mapControl()) {
return false;
}
lastCheckTime = currentTime;
}
}
}
}
}
zos.closeEntry();
LogUtils.d(TAG, "添加文件到ZIP: " + entryName);
return true;
}
/**
* 获取文件相对于基础目录的路径
*
* @param file 文件
* @param baseDir 基础目录
* @return 相对路径
*/
private String getRelativePath(File file, File baseDir) {
Path filePath = file.toPath();
Path basePath = baseDir.toPath();
return basePath.relativize(filePath).toString().replace(File.separator, "/");
}
}
】