项目源代码中的File.separator作用

本文探讨了file.separator和/在不同操作系统中的作用。在Windows中,和/都可用作文件分隔符,而在Linux中仅接受/。File.separator作为系统默认的文件分隔符,确保了代码在Windows和Linux等不同系统间的一致性和兼容性。

file.separator 和 / 区别

 
在windows中的文件分隔符是 \ 和 /都可以

但是在Linux中,文件分隔符只能是/

所以用了\\的程序在Linux下会出问题。

而File.separator是系统默认的文件分割符号,屏蔽了这些系统的区别。

用File.separator保证了在任何系统下不会出错。

转载于:https://www.cnblogs.com/ffzzcommsoft/p/9442681.html

package com.example.demo.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.lang.UUID; import cn.hutool.core.thread.ThreadFactoryBuilder; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.demo.dao.entity.WExecuteHost; import com.example.demo.dao.entity.WHostProcess; import com.example.demo.dao.entity.WPersonalHost; import com.example.demo.dao.mapper.WExecuteHostMapper; import com.example.demo.request.ProcessRequest; import com.example.demo.service.WExecuteHostService; import com.example.demo.service.WHostProcessService; import com.example.demo.service.WPersonalHostService; import lombok.Data; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.interceptor.TransactionAspectSupport; import javax.annotation.PreDestroy; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Matcher; import java.util.regex.Pattern; @Service public class WExecuteHostServiceImpl extends ServiceImpl<WExecuteHostMapper, WExecuteHost> implements WExecuteHostService { @Autowired private WPersonalHostService wPersonalHostService; @Autowired private WHostProcessService wHostProcessService; @Data private static class UserSession { private Process cmdProcess; private volatile boolean isProcessRunning; private String sessionId; private String logFilePath; private final Queue<String> logBuffer = new ConcurrentLinkedQueue<>(); private static final int BATCH_SIZE = 50; // 批量写入阈值 // 命令执行状态锁 private final AtomicBoolean isExecuting = new AtomicBoolean(false); } private final Map<String, UserSession> userSessions = new ConcurrentHashMap<>(); private final SimpMessagingTemplate messagingTemplate; // 异步日志写入线程池 private static final ExecutorService LOG_WRITER_POOL = Executors.newCachedThreadPool( new ThreadFactoryBuilder().setNamePrefix("log-writer-").build()); // 日志刷新调度器 private static final ScheduledExecutorService LOG_FLUSH_SCHEDULER = Executors.newSingleThreadScheduledExecutor(); public WExecuteHostServiceImpl(SimpMessagingTemplate messagingTemplate) { this.messagingTemplate = messagingTemplate; startLogFlushService(); } // 初始化日志刷新服务 private void startLogFlushService() { LOG_FLUSH_SCHEDULER.scheduleAtFixedRate(() -> { userSessions.values().forEach(session -> { if (!session.getLogBuffer().isEmpty()) { List<String> batch = CollUtil.newArrayList(session.getLogBuffer()); session.getLogBuffer().clear(); asyncWriteLog(session.getLogFilePath(), String.join("\n", batch)); } }); }, 0, 1, TimeUnit.SECONDS); } @Override public void executeCommand(String command, String host, String userId) { // 0. ABORT命令特殊处理(优先处理终止请求) if ("ABORT".equalsIgnoreCase(command)) { handleAbort(userId); return; } // 1. 权限校验 if (!validateUserHost(userId, host)) { sendError("无权访问该主机", userId); return; } // 2. 检查用户当前会话状态 UserSession session = userSessions.get(userId); if (session != null && session.isExecuting.get()) { sendError("已有命令执行中,请等待完成或使用ABORT终止", userId); return; } // 3. 创建新会话(带原子状态检查) session = userSessions.computeIfAbsent(userId, key -> { UserSession newSession = createNewSession(userId, host); if (newSession != null) { newSession.isExecuting.set(true); // 标记为执行中 } return newSession; }); if (session == null) return; // 4. 写入日志并执行命令 try { // 确保获得执行锁 if (!session.isExecuting.compareAndSet(true, true)) { sendError("命令执行冲突,请重试", userId); return; } session.getLogBuffer().offer("——————————————— " + DateUtil.now() + " ———————————————"); // 发送命令到进程 IoUtil.write(session.getCmdProcess().getOutputStream(), Charset.forName("gbk"), true, command + "\n"); } catch (Exception e) { session.isExecuting.set(false); // 发生异常时释放锁 sendError("命令发送失败: " + e.getMessage(), userId); } } @Override public Boolean isCommandExecuting(String userId) { UserSession session = userSessions.get(userId); return session != null && session.isExecuting.get(); } @Override public void handleAbort(String userId) { UserSession session = userSessions.get(userId); if (session == null || session.getCmdProcess() == null) { sendError("没有活动的命令进程", userId); return; } try { long pid = session.getCmdProcess().pid(); System.out.println("Attempting to kill process with PID: " + pid); // 使用 taskkill 命令终止进程 ProcessBuilder taskKill = new ProcessBuilder("taskkill", "/F", "/T", "/PID", String.valueOf(pid)); Process killProcess = taskKill.start(); // 等待命令执行完成 int exitCode = killProcess.waitFor(); System.out.println("taskkill exit code: " + exitCode); if (exitCode == 0) { // 进程终止成功 session.isExecuting.set(false); cleanupSession(userId); messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, "✔️" + "进程已通过 taskkill 终止 (PID: " + pid + ")"); messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, ""); messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, System.getProperty("user.dir") + ">"); } else { // 进程终止失败 sendError("终止进程失败,错误码: " + exitCode, userId); } } catch (IOException | InterruptedException e) { System.err.println("Error killing process: " + e.getMessage()); sendError("终止进程失败: " + e.getMessage(), userId); } } @Override public String startProcess(ProcessRequest processRequest) { try { // 数据库表新增数据 String p13 = processRequest.getP13().trim(); String processName = processRequest.getProcessName().trim(); String productNumber = processRequest.getProductNumber().trim(); String executeHost = processRequest.getExecuteHost().trim(); String department = processRequest.getDepartment().trim(); String version = processRequest.getVersion().trim(); if (StrUtil.isEmpty(p13) || StrUtil.isEmpty(processName) || StrUtil.isEmpty(productNumber) || StrUtil.isEmpty(executeHost) || StrUtil.isEmpty(department) || StrUtil.isEmpty(version)) { return "新增进程失败。"; } WHostProcess wHostProcess = new WHostProcess(); wHostProcess.setP13(p13); wHostProcess.setProcessName(processName); wHostProcess.setProductNumber(productNumber); wHostProcess.setHost(executeHost); wHostProcess.setPid(null); wHostProcess.setDepartment(department); wHostProcess.setState("离线"); wHostProcess.setVersion(version); wHostProcess.setBeginTime(new Date()); boolean saveResult = wHostProcessService.save(wHostProcess); if (saveResult) { LambdaQueryWrapper<WPersonalHost> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper .eq(WPersonalHost::getExecuteHost, processRequest.getExecuteHost()) .eq(WPersonalHost::getSharedHost, processRequest.getSharedHost()); WPersonalHost wPersonalHost = wPersonalHostService.getOne(queryWrapper); // 执行py启动命令 //todo 后续动态 String pythonEXEPath = "D:\\miniforge\\envs" + File.separator + p13 + File.separator + "python" + wPersonalHost.getPythonEnv() + File.separator + "python.exe"; String mainPyPath = System.getProperty("user.dir") + File.separator + "python-package" + File.separator + executeHost + File.separator + p13 + File.separator + "test" + File.separator + "main.py"; executeCommand(pythonEXEPath + " " + mainPyPath, processRequest.getExecuteHost(), processRequest.getP13()); return "正在启动项目..."; } } catch (Exception e) { e.printStackTrace(); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } return "新增进程失败。"; } private boolean validateUserHost(String userId, String executeHost) { LambdaQueryWrapper<WPersonalHost> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(WPersonalHost::getP13, userId) .eq(WPersonalHost::getExecuteHost, executeHost) .eq(WPersonalHost::getState, "在线"); return wPersonalHostService.getOne(queryWrapper) != null; } private UserSession createNewSession(String userId, String executeHost) { try { UserSession session = new UserSession(); session.setSessionId(UUID.randomUUID().toString()); session.setLogFilePath(initLogFile(userId, executeHost)); // 启动CMD进程(带唯一标题) ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/k", "title " + generateUniqueTitle(userId)); session.setCmdProcess(pb.redirectErrorStream(true).start()); // 启动输出监听线程 startOutputThread(session, userId); return session; } catch (IOException e) { sendError("进程启动失败: " + e.getMessage(), userId); return null; } } private String initLogFile(String userId, String executeHost) { // 1. 构建基础路径(使用File.separator) String baseDir = FileUtil.normalize( System.getProperty("user.dir") + File.separator + "command-log"); // 2. 构建安全路径(统一使用File.separator) String safePath = FileUtil.normalize( baseDir + File.separator + userId + File.separator + executeHost + File.separator + "项目名称"); // 3. 安全校验(现在路径分隔符一致) if (!safePath.startsWith(baseDir)) { throw new SecurityException("非法日志路径: " + safePath); } // 4. 创建目录(自动处理路径分隔符) FileUtil.mkdir(safePath); // 5. 生成日志文件 String logFileName = DateUtil.today() + ".log"; return FileUtil.touch(safePath + File.separator + logFileName).getAbsolutePath(); } private void startOutputThread(UserSession session, String userId) { new Thread(() -> { try (BufferedReader reader = new BufferedReader( new InputStreamReader(session.getCmdProcess().getInputStream(), "GBK"))) { String line; while ((line = reader.readLine()) != null) { messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, line); session.getLogBuffer().offer(line); } } catch (Exception e) { sendError("输出流异常: " + e.getMessage(), userId); } finally { session.isExecuting.set(false); // 命令结束释放锁 cleanupSession(userId); // 通知前端命令执行结束 messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, "⏹ 该命令执行已结束"); } }).start(); } private void asyncWriteLog(String logFilePath, String content) { CompletableFuture.runAsync(() -> { try { // 替换掉日志文件中没用的信息,如多余的路径信息 String currentDir = System.getProperty("user.dir"); String escapedDir = currentDir.replace("\\", "\\\\"); String regex = "(?m)^\\s*" + escapedDir + ">(?!\\S)\\s*"; // 创建 Pattern 和 Matcher 对象 Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(content); // 检查是否存在匹配的模式 if (matcher.find()) { // 如果存在匹配,则进行替换 String cleaned = content.replaceAll(regex, ""); FileUtil.appendString(cleaned + System.lineSeparator(), logFilePath, "GBK"); } else { FileUtil.appendString(content + System.lineSeparator(), logFilePath, "GBK"); } } catch (Exception e) { System.err.println("日志写入失败: " + e.getMessage()); } }, LOG_WRITER_POOL); } private void cleanupSession(String userId) { UserSession session = userSessions.remove(userId); if (session != null) { try { if (session.getCmdProcess() != null) { session.getCmdProcess().destroyForcibly(); } // 强制将剩余日志写入文件(新增代码) if (!session.getLogBuffer().isEmpty()) { asyncWriteLog(session.getLogFilePath(), String.join("\n", session.getLogBuffer())); session.getLogBuffer().clear(); } } catch (Exception ignored) { } } } @PreDestroy public void cleanup() { LOG_FLUSH_SCHEDULER.shutdown(); LOG_WRITER_POOL.shutdown(); userSessions.forEach((userId, session) -> { try { if (session.getCmdProcess() != null) { session.getCmdProcess().destroyForcibly(); } } catch (Exception ignored) { } }); userSessions.clear(); } /** * 发送错误日志 */ private void sendError(String message, String userId) { try { messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, "❌" + message); } catch (Exception ignored) { } } /** * 生成cmd窗口唯一id */ private String generateUniqueTitle(String userId) { return "CMD_SESSION_" + userId + "_" + System.currentTimeMillis(); } } 仔细阅读我的代码,现在有个bug,我执行下面的main.py文件,会报错请输入你的名字: 发生未知错误: EOF when reading a line import random import sys from datetime import datetime def generate_random_number(min_val=1, max_val=100): """ 生成一个指定范围内的随机整数 参数: min_val (int): 最小值,默认为1 max_val (int): 最大值,默认为100 返回: int: 随机生成的整数 """ return random.randint(min_val, max_val) def check_even_odd(number): """ 检查一个数字是奇数还是偶数 参数: number (int): 要检查的数字 返回: str: "偶数" 或 "奇数" """ return "偶数" if number % 2 == 0 else "奇数" def greet_user(name): """ 向用户问好 参数: name (str): 用户名 """ print(f"你好, {name}! 当前时间是: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") def main(): """ 主函数 """ print("欢迎使用随机数生成器!") try: user_name = input("请输入你的名字: ") greet_user(user_name) count = int(input("你想生成多少个随机数? (1-10): ")) if count < 1 or count > 10: print("请输入1到10之间的数字!") return for i in range(count): num = generate_random_number() print(f"随机数 #{i+1}: {num} ({check_even_odd(num)})") print("感谢使用!") except ValueError: print("错误: 请输入有效的数字!") except KeyboardInterrupt: print("\n程序被用户中断") except Exception as e: print(f"发生未知错误: {e}") if __name__ == "__main__": main()
06-18
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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值