日志相关→LogUtils

本文介绍了一个用于Android的日志工具类的设计与实现细节,包括不同类型的日志输出、日志格式化、边界显示以及日志文件存储等功能。
   
  import android.os.Environment;
  import android.support.annotation.IntDef;
  import android.util.Log;
   
  import org.json.JSONArray;
  import org.json.JSONException;
  import org.json.JSONObject;
   
  import java.io.BufferedWriter;
  import java.io.File;
  import java.io.FileWriter;
  import java.io.IOException;
  import java.io.StringReader;
  import java.io.StringWriter;
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  import java.util.Formatter;
  import java.util.Locale;
   
  import javax.xml.transform.OutputKeys;
  import javax.xml.transform.Source;
  import javax.xml.transform.Transformer;
  import javax.xml.transform.TransformerFactory;
  import javax.xml.transform.stream.StreamResult;
  import javax.xml.transform.stream.StreamSource;
   
  /**
  * <pre>
  * author: Blankj
  * blog : http://blankj.com
  * time : 2016/9/21
  * desc : 日志相关工具类
  * </pre>
  */
  public final class LogUtils {
   
  private LogUtils() {
  throw new UnsupportedOperationException("u can't instantiate me...");
  }
   
  public static final int V = 0x01;
  public static final int D = 0x02;
  public static final int I = 0x04;
  public static final int W = 0x08;
  public static final int E = 0x10;
  public static final int A = 0x20;
   
  @IntDef({V, D, I, W, E, A})
  @Retention(RetentionPolicy.SOURCE)
  public @interface TYPE {
  }
   
  private static final int FILE = 0xF1;
  private static final int JSON = 0xF2;
  private static final int XML = 0xF4;
   
  private static String dir; // log存储目录
  private static boolean sLogSwitch = true; // log总开关
  private static String sGlobalTag = null; // log标签
  private static boolean sTagIsSpace = true; // log标签是否为空白
  private static boolean sLog2FileSwitch = false;// log写入文件开关
  private static boolean sLogBorderSwitch = true; // log边框开关
  private static int sLogFilter = V; // log过滤器
   
  private static final String TOP_BORDER = "╔═══════════════════════════════════════════════════════════════════════════════════════════════════";
  private static final String LEFT_BORDER = "";
  private static final String BOTTOM_BORDER = "╚═══════════════════════════════════════════════════════════════════════════════════════════════════";
  private static final String LINE_SEPARATOR = System.getProperty("line.separator");
   
  private static final int MAX_LEN = 4000;
  private static final String NULL_TIPS = "Log with null object.";
  private static final String NULL = "null";
  private static final String ARGS = "args";
   
  public static class Builder {
   
  public Builder() {
  if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
  dir = Utils.getContext().getExternalCacheDir() + File.separator + "log" + File.separator;
  } else {
  dir = Utils.getContext().getCacheDir() + File.separator + "log" + File.separator;
  }
  }
   
  public Builder setGlobalTag(String tag) {
  if (!isSpace(tag)) {
  LogUtils.sGlobalTag = tag;
  sTagIsSpace = false;
  } else {
  LogUtils.sGlobalTag = "";
  sTagIsSpace = true;
  }
  return this;
  }
   
  public Builder setLogSwitch(boolean logSwitch) {
  LogUtils.sLogSwitch = logSwitch;
  return this;
  }
   
  public Builder setLog2FileSwitch(boolean log2FileSwitch) {
  LogUtils.sLog2FileSwitch = log2FileSwitch;
  return this;
  }
   
  public Builder setBorderSwitch(boolean borderSwitch) {
  LogUtils.sLogBorderSwitch = borderSwitch;
  return this;
  }
   
  public Builder setLogFilter(@TYPE int logFilter) {
  LogUtils.sLogFilter = logFilter;
  return this;
  }
  }
   
  public static void v(Object contents) {
  log(V, sGlobalTag, contents);
  }
   
  public static void v(String tag, Object... contents) {
  log(V, tag, contents);
  }
   
  public static void d(Object contents) {
  log(D, sGlobalTag, contents);
  }
   
  public static void d(String tag, Object... contents) {
  log(D, tag, contents);
  }
   
  public static void i(Object contents) {
  log(I, sGlobalTag, contents);
  }
   
  public static void i(String tag, Object... contents) {
  log(I, tag, contents);
  }
   
  public static void w(Object contents) {
  log(W, sGlobalTag, contents);
  }
   
  public static void w(String tag, Object... contents) {
  log(W, tag, contents);
  }
   
  public static void e(Object contents) {
  log(E, sGlobalTag, contents);
  }
   
  public static void e(String tag, Object... contents) {
  log(E, tag, contents);
  }
   
  public static void a(Object contents) {
  log(A, sGlobalTag, contents);
  }
   
  public static void a(String tag, Object... contents) {
  log(A, tag, contents);
  }
   
  public static void file(Object contents) {
  log(FILE, sGlobalTag, contents);
  }
   
  public static void file(String tag, Object contents) {
  log(FILE, tag, contents);
  }
   
  public static void json(String contents) {
  log(JSON, sGlobalTag, contents);
  }
   
  public static void json(String tag, String contents) {
  log(JSON, tag, contents);
  }
   
  public static void xml(String contents) {
  log(XML, sGlobalTag, contents);
  }
   
  public static void xml(String tag, String contents) {
  log(XML, tag, contents);
  }
   
  private static void log(int type, String tag, Object... contents) {
  if (!sLogSwitch) return;
  final String[] processContents = processContents(type, tag, contents);
  tag = processContents[0];
  String msg = processContents[1];
  switch (type) {
  case V:
  case D:
  case I:
  case W:
  case E:
  case A:
  if (V == sLogFilter || type >= sLogFilter) {
  printLog(type, tag, msg);
  }
  if (sLog2FileSwitch) {
  print2File(tag, msg);
  }
  break;
  case FILE:
  print2File(tag, msg);
  break;
  case JSON:
  printLog(D, tag, msg);
  break;
  case XML:
  printLog(D, tag, msg);
  break;
  }
   
  }
   
  private static String[] processContents(int type, String tag, Object... contents) {
  StackTraceElement targetElement = Thread.currentThread().getStackTrace()[5];
  String className = targetElement.getClassName();
  String[] classNameInfo = className.split("\\.");
  if (classNameInfo.length > 0) {
  className = classNameInfo[classNameInfo.length - 1];
  }
  if (className.contains("$")) {
  className = className.split("\\$")[0];
  }
  if (!sTagIsSpace) {// 如果全局tag不为空,那就用全局tag
  tag = sGlobalTag;
  } else {// 全局tag为空时,如果传入的tag为空那就显示类名,否则显示tag
  tag = isSpace(tag) ? className : tag;
  }
   
  String head = new Formatter()
  .format("Thread: %s, %s(%s.java:%d)" + LINE_SEPARATOR,
  Thread.currentThread().getName(),
  targetElement.getMethodName(),
  className,
  targetElement.getLineNumber())
  .toString();
  String msg = NULL_TIPS;
  if (contents != null) {
  if (contents.length == 1) {
  Object object = contents[0];
  msg = object == null ? NULL : object.toString();
  if (type == JSON) {
  msg = formatJson(msg);
  } else if (type == XML) {
  msg = formatXml(msg);
  }
  } else {
  StringBuilder sb = new StringBuilder();
  for (int i = 0, len = contents.length; i < len; ++i) {
  Object content = contents[i];
  sb.append(ARGS)
  .append("[")
  .append(i)
  .append("]")
  .append(" = ")
  .append(content == null ? NULL : content.toString())
  .append(LINE_SEPARATOR);
  }
  msg = sb.toString();
  }
  }
  if (sLogBorderSwitch) {
  StringBuilder sb = new StringBuilder();
  String[] lines = msg.split(LINE_SEPARATOR);
  for (String line : lines) {
  sb.append(LEFT_BORDER).append(line).append(LINE_SEPARATOR);
  }
  msg = sb.toString();
  }
  return new String[]{tag, head + msg};
  }
   
  private static String formatJson(String json) {
  try {
  if (json.startsWith("{")) {
  json = new JSONObject(json).toString(4);
  } else if (json.startsWith("[")) {
  json = new JSONArray(json).toString(4);
  }
  } catch (JSONException e) {
  e.printStackTrace();
  }
  return json;
  }
   
  private static String formatXml(String xml) {
  try {
  Source xmlInput = new StreamSource(new StringReader(xml));
  StreamResult xmlOutput = new StreamResult(new StringWriter());
  Transformer transformer = TransformerFactory.newInstance().newTransformer();
  transformer.setOutputProperty(OutputKeys.INDENT, "yes");
  transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
  transformer.transform(xmlInput, xmlOutput);
  xml = xmlOutput.getWriter().toString().replaceFirst(">", ">" + LINE_SEPARATOR);
  } catch (Exception e) {
  e.printStackTrace();
  }
  return xml;
  }
   
  private static void printLog(int type, String tag, String msg) {
  if (sLogBorderSwitch) printBorder(type, tag, true);
  int len = msg.length();
  int countOfSub = len / MAX_LEN;
  if (countOfSub > 0) {
  int index = 0;
  String sub;
  for (int i = 0; i < countOfSub; i++) {
  sub = msg.substring(index, index + MAX_LEN);
  printSubLog(type, tag, sub);
  index += MAX_LEN;
  }
  printSubLog(type, tag, msg.substring(index, len));
  } else {
  printSubLog(type, tag, msg);
  }
  if (sLogBorderSwitch) printBorder(type, tag, false);
  }
   
  private static void printSubLog(final int type, final String tag, String msg) {
  if (sLogBorderSwitch) msg = LEFT_BORDER + msg;
  switch (type) {
  case V:
  Log.v(tag, msg);
  break;
  case D:
  Log.d(tag, msg);
  break;
  case I:
  Log.i(tag, msg);
  break;
  case W:
  Log.w(tag, msg);
  break;
  case E:
  Log.e(tag, msg);
  break;
  case A:
  Log.wtf(tag, msg);
  break;
  }
  }
   
  private static void printBorder(int type, String tag, boolean isTop) {
  String border = isTop ? TOP_BORDER : BOTTOM_BORDER;
  switch (type) {
  case V:
  Log.v(tag, border);
  break;
  case D:
  Log.d(tag, border);
  break;
  case I:
  Log.i(tag, border);
  break;
  case W:
  Log.w(tag, border);
  break;
  case E:
  Log.e(tag, border);
  break;
  case A:
  Log.wtf(tag, border);
  break;
  }
  }
   
  private synchronized static void print2File(final String tag, final String msg) {
  Date now = new Date();
  String date = new SimpleDateFormat("MM-dd", Locale.getDefault()).format(now);
  final String fullPath = dir + date + ".txt";
  if (!createOrExistsFile(fullPath)) {
  Log.e(tag, "log to " + fullPath + " failed!");
  return;
  }
  String time = new SimpleDateFormat("MM-dd HH:mm:ss.SSS ", Locale.getDefault()).format(now);
  StringBuilder sb = new StringBuilder();
  if (sLogBorderSwitch) sb.append(TOP_BORDER).append(LINE_SEPARATOR);
  sb.append(time)
  .append(tag)
  .append(": ")
  .append(msg)
  .append(LINE_SEPARATOR);
  if (sLogBorderSwitch) sb.append(BOTTOM_BORDER).append(LINE_SEPARATOR);
  final String dateLogContent = sb.toString();
  new Thread(new Runnable() {
  @Override
  public void run() {
  BufferedWriter bw = null;
  try {
  bw = new BufferedWriter(new FileWriter(fullPath, true));
  bw.write(dateLogContent);
  Log.d(tag, "log to " + fullPath + " success!");
  } catch (IOException e) {
  e.printStackTrace();
  Log.e(tag, "log to " + fullPath + " failed!");
  } finally {
  try {
  if (bw != null) {
  bw.close();
  }
  } catch (IOException e) {
  e.printStackTrace();
  }
  }
  }
  }).start();
  }
   
  private static boolean createOrExistsFile(String filePath) {
  return createOrExistsFile(isSpace(filePath) ? null : new File(filePath));
  }
   
  private static boolean createOrExistsFile(File file) {
  if (file == null) return false;
  if (file.exists()) return file.isFile();
  if (!createOrExistsDir(file.getParentFile())) return false;
  try {
  return file.createNewFile();
  } catch (IOException e) {
  e.printStackTrace();
  return false;
  }
  }
   
  private static boolean createOrExistsDir(File file) {
  return file != null && (file.exists() ? file.isDirectory() : file.mkdirs());
  }
   
  private static boolean isSpace(String s) {
  if (s == null) return true;
  for (int i = 0, len = s.length(); i < len; ++i) {
  if (!Character.isWhitespace(s.charAt(i))) {
  return false;
  }
  }
  return true;
  }
  }
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; LogUtils.i("开始解压ZIP文件: " + zipFilePath + " 到目录: " + outputDir); // 创建输出目录(如果不存在) File dir = new File(outputDir); if (!dir.exists()) { LogUtils.d("尝试创建输出目录: " + outputDir); if (!dir.mkdirs()) { LogUtils.e("无法创建输出目录: " + outputDir); return false; } LogUtils.i("成功创建输出目录: " + outputDir); } // 获取输出目录的规范路径用于安全检查 String canonicalOutputDir; try { canonicalOutputDir = dir.getCanonicalPath(); LogUtils.d("输出目录规范路径: " + canonicalOutputDir); } catch (IOException e) { LogUtils.e("获取输出目录规范路径失败: " + e.getMessage()); return false; } try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFilePath)))) { LogUtils.d("打开ZIP输入流成功"); ZipEntry entry; int entryCount = 0; while ((entry = zis.getNextEntry()) != null) { entryCount++; String originalEntryName = entry.getName(); LogUtils.d("处理条目 #" + entryCount + ": " + originalEntryName + " | 目录: " + entry.isDirectory() + " | 大小: " + entry.getSize() + " bytes"); // 规范化路径处理 String entryName = normalizePath(originalEntryName); if (entryName.isEmpty()) { LogUtils.e("跳过无效条目: " + originalEntryName); continue; } LogUtils.d("规范化后路径: " + entryName); File outputFile = new File(outputDir, entryName); // 详细路径安全日志 try { String canonicalPath = outputFile.getCanonicalPath(); LogUtils.d("目标文件规范路径: " + canonicalPath); // 路径遍历安全检查 if (!canonicalPath.startsWith(canonicalOutputDir + File.separator)) { LogUtils.e("安全违规: 条目 " + originalEntryName + " 试图逃逸到 " + canonicalPath); success = false; continue; } } catch (IOException e) { LogUtils.e("路径解析错误: " + outputFile.getAbsolutePath() + " | 错误: " + e.getMessage()); success = false; continue; } // 创建父目录(如果需要) File parentDir = outputFile.getParentFile(); if (parentDir != null && !parentDir.exists()) { LogUtils.d("尝试创建父目录: " + parentDir.getAbsolutePath()); if (!parentDir.mkdirs()) { LogUtils.e("无法创建父目录: " + parentDir.getAbsolutePath()); success = false; continue; } LogUtils.i("成功创建父目录: " + parentDir.getAbsolutePath()); } if (!entry.isDirectory()) { LogUtils.d("解压文件到: " + outputFile.getAbsolutePath()); try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outputFile))) { byte[] buffer = new byte[BUFFER_SIZE]; int bytesRead; long totalBytes = 0; while ((bytesRead = zis.read(buffer)) != -1) { bos.write(buffer, 0, bytesRead); totalBytes += bytesRead; // 安全检查逻辑(每秒最多1次) long currentTime = System.currentTimeMillis(); if (currentTime - lastCheckTime > 1000) { synchronized (this) { if (currentTime - lastCheckTime > 1000) { LogUtils.d("执行安全检测..."); if (!HmiJNIImpl.getInstance().mapControl()) { LogUtils.e("安全检测失败,终止解压"); return false; } lastCheckTime = currentTime; } } } } LogUtils.i("成功解压文件: " + outputFile.getName() + " | 大小: " + totalBytes + " bytes"); } catch (IOException e) { LogUtils.e("写入文件失败: " + outputFile.getAbsolutePath() + " | 错误: " + e.getMessage()); success = false; // 删除部分写入的文件 if (outputFile.exists() && !outputFile.delete()) { LogUtils.e("无法删除部分写入的文件: " + outputFile.getAbsolutePath()); } } } else { LogUtils.d("创建目录: " + outputFile.getAbsolutePath()); if (!outputFile.exists()) { if (!outputFile.mkdirs()) { LogUtils.e("无法创建目录: " + outputFile.getAbsolutePath()); success = false; } else { LogUtils.i("成功创建目录: " + outputFile.getAbsolutePath()); } } else { LogUtils.d("目录已存在: " + outputFile.getAbsolutePath()); } } zis.closeEntry(); LogUtils.d("完成处理条目: " + originalEntryName); } LogUtils.i("处理完成所有条目,共 " + entryCount + " 个"); } catch (IOException e) { LogUtils.e("解压ZIP文件时发生错误: " + e.getMessage()); success = false; } // 结果处理 if (success) { LogUtils.i("解压成功,尝试删除原始ZIP文件: " + zipFilePath); File zipFile = new File(zipFilePath); if (zipFile.delete()) { LogUtils.i("成功删除原始ZIP文件: " + zipFilePath); } else { LogUtils.e("无法删除原始ZIP文件: " + zipFilePath); success = false; } } else { LogUtils.e("解压过程中遇到错误,保留原始ZIP文件"); } LogUtils.i("解压结果: " + (success ? "成功" : "失败")); return success; } // 增强的路径规范化方法 private String normalizePath(String path) { if (path == null || path.trim().isEmpty()) { LogUtils.e("收到空路径"); return ""; } LogUtils.d("原始路径: " + path); // 统一路径分隔符并压缩连续分隔符 String normalized = path.replace('\\', '/') .replaceAll("/+", "/") // 合并所有连续斜杠 .trim(); // 移除开头斜杠 if (normalized.startsWith("/")) { normalized = normalized.substring(1); LogUtils.d("移除开头斜杠: " + normalized); } // 处理Windows盘符路径 if (normalized.matches("[a-zA-Z]:[/\\\\].*")) { LogUtils.e("检测到绝对路径: " + path); return ""; } // 处理路径遍历攻击 if (normalized.contains("..")) { // 精确检测路径遍历序列 if (normalized.contains("../") || normalized.contains("/..") || normalized.startsWith("..") || normalized.endsWith("..")) { LogUtils.e("检测到路径遍历攻击: " + path); return ""; } } LogUtils.d("规范化后路径: " + normalized); return normalized; } /** * 压缩文件或目录到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, "/"); } } unzip 输入哪些?
07-29
public boolean dataVerification(String verifyDataPath) { LogUtils.i(TAG, "dataVerification[verifyDataPath]:" + verifyDataPath); String signPath = "/data/data/com.isa.navi/sign/"; if(!mapControl()) { return false; } //解压加密数据 LogUtils.i(TAG, "verifyDataPath[" + verifyDataPath + "] -> signPath[" + signPath + "]"); if(!unzipFile(verifyDataPath, signPath)) { //删除解密验签中间文件 if(!deleteDirectory(signPath)) { LogUtils.e(TAG, "无法删除解密验签中间文件!"); } return false; } if(!mapControl()) { return false; } //提取签名文件以及加密文件的绝对路径 String[] temp = ZipUtils.getInstance().findEncryptedZipFiles(signPath); String aesDaraPath = temp[1]; String signDataPtah = temp[0]; LogUtils.i(TAG, "aesDaraPath:" + aesDaraPath); LogUtils.i(TAG, "signDataPtah" + signDataPtah); if(!mapControl()) { return false; } //验证签名 if(!verifySignature(aesDaraPath, signDataPtah)) { LogUtils.e(TAG, "verifySignature fail!"); //删除解密验签中间文件 if(!deleteDirectory(signPath)) { LogUtils.e(TAG, "无法删除解密验签中间文件!"); } return false; } if(!mapControl()) { return false; } //对称解密Zip if(!decryptFile(aesDaraPath, verifyDataPath)) { LogUtils.e(TAG, "decryptFile fail!"); //删除解密验签中间文件 if(!deleteDirectory(signPath)) { LogUtils.e(TAG, "无法删除解密验签中间文件!"); } return false; } //删除解密验签中间文件 if(!deleteDirectory(signPath)) { LogUtils.e(TAG, "无法删除解密验签中间文件!"); } LogUtils.i(TAG, "dataVerification success"); return true; } 这段代码涉及哪些路径,用于干什么?
07-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值