当前位置: 首页 > news >正文

软件打包前进行文件去重

首先,直接对软件目录执行 zip 压缩,压缩算法无法解决文件重复的问题,如果软件目录中,重复文件比较多,零散的分布在各个子目录中,那么对目录中的文件进行去重,会节省很多空间。

1. 去重脚本

#!/bin/bash# 检查输入目录
if [ $# -ne 1 ] || [ ! -d "$1" ]; thenecho "用法: $0 <目标目录>"exit 1
fiTARGET_DIR="$1"# 生成文件路径与哈希值的映射(排除目录)
find "$TARGET_DIR" -type f -print0 | xargs -0 md5sum | sort > /tmp/file_hashes.txt# 提取重复哈希值(出现次数 > 1)
awk '{print $1}' /tmp/file_hashes.txt | uniq -d > /tmp/duplicate_hashes.txt# 遍历重复哈希值,保留第一个文件,删除其余重复文件
while read -r hash; do# 查找该哈希值对应的所有文件,按路径排序files=$(grep "^$hash " /tmp/file_hashes.txt | awk '{print $2}' | sort)# 保留第一个文件,删除后续文件first_file=$(echo "$files" | head -n 1)other_files=$(echo "$files" | tail -n +2)if [ -n "$other_files" ]; thenecho "保留: $first_file"echo "删除重复文件: $other_files"rm -f $other_files  # 确认无误后删除此行的注释fi
done < /tmp/duplicate_hashes.txtecho "去重完成"

2 去重 Java 代码

import java.io.*;
import java.nio.file.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;public class RemoveDuplicates {public static void main(String[] args) {if (args.length == 0) {System.out.println("请指定要去重的目录路径");System.out.println("用法: java FileDeduplicator [目录路径]");return;}String directoryPath = "args[0]";File directory = new File(directoryPath);if (!directory.exists() || !directory.isDirectory()) {System.out.println("指定的路径不存在或不是目录");return;}try {// 按文件大小分组,只有大小相同的文件才可能是重复文件Map<Long, List<File>> filesBySize = groupFilesBySize(directory);// 对每个大小组中的文件计算哈希值,找出重复文件Map<String, List<File>> duplicateFiles = findDuplicatesByContent(filesBySize);// 处理重复文件(默认保留一个,删除其他)processDuplicates(duplicateFiles);} catch (IOException e) {System.out.println("处理文件时出错: " + e.getMessage());}}/*** 按文件大小分组*/private static Map<Long, List<File>> groupFilesBySize(File directory) throws IOException {Map<Long, List<File>> filesBySize = new HashMap<>();Files.walk(Paths.get(directory.getAbsolutePath())).filter(Files::isRegularFile).forEach(path -> {try {long size = Files.size(path);File file = path.toFile();filesBySize.computeIfAbsent(size, k -> new ArrayList<>()).add(file);} catch (IOException e) {System.out.println("无法获取文件大小: " + path + " - " + e.getMessage());}});// 移除只有一个文件的分组(不可能是重复文件)filesBySize.values().removeIf(list -> list.size() <= 1);return filesBySize;}/*** 对大小相同的文件计算哈希值,找出内容相同的重复文件*/private static Map<String, List<File>> findDuplicatesByContent(Map<Long, List<File>> filesBySize) throws IOException {Map<String, List<File>> duplicates = new HashMap<>();for (List<File> files : filesBySize.values()) {for (File file : files) {String hash = calculateFileHash(file);duplicates.computeIfAbsent(hash, k -> new ArrayList<>()).add(file);}}// 移除只有一个文件的分组(不是重复文件)duplicates.values().removeIf(list -> list.size() <= 1);return duplicates;}/*** 计算文件的MD5哈希值,用于判断文件内容是否相同*/private static String calculateFileHash(File file) throws IOException {try (InputStream is = new FileInputStream(file)) {MessageDigest md = MessageDigest.getInstance("MD5");byte[] buffer = new byte[8192];int bytesRead;while ((bytesRead = is.read(buffer)) != -1) {md.update(buffer, 0, bytesRead);}byte[] hashBytes = md.digest();// 转换为十六进制字符串StringBuilder sb = new StringBuilder();for (byte b : hashBytes) {sb.append(String.format("%02x", b));}return sb.toString();} catch (NoSuchAlgorithmException e) {// MD5算法是Java标准库自带的,理论上不会抛出此异常throw new RuntimeException("无法获取MD5算法实例", e);}}/*** 处理重复文件,保留第一个,删除其他*/private static void processDuplicates(Map<String, List<File>> duplicateFiles) {if (duplicateFiles.isEmpty()) {System.out.println("未发现重复文件");return;}System.out.println("发现 " + duplicateFiles.size() + " 组重复文件:");int totalDeleted = 0;long size = 0;for (List<File> duplicates : duplicateFiles.values()) {System.out.println("\n重复文件组(共 " + duplicates.size() + " 个):");// 保留第一个文件,删除其他File keepFile = duplicates.get(0);System.out.println("保留: " + keepFile.getAbsolutePath());for (int i = 1; i < duplicates.size(); i++) {File fileToDelete = duplicates.get(i);size+= fileToDelete.length();if (fileToDelete.delete()) {System.out.println("已删除: " + fileToDelete.getAbsolutePath());totalDeleted++;} else {System.out.println("无法删除: " + fileToDelete.getAbsolutePath());}}}System.out.println("\n处理完成,共删除 " + totalDeleted + " 个重复文件");System.out.println("\n处理完成,共删除 " + size/(1024*1024.0) + " MB");}
}

3 使用硬链接

在 Linux 中,硬链接(Hard Link) 是文件系统中同一个文件(数据块)的多个引用。

特性硬链接软链接(符号链接)
存储空间不额外占用占用少量空间(存储路径)
跨文件系统不支持支持
链接目录受限(需 root)支持
原始文件删除后仍可访问(数据保留)失效(悬空链接)
文件类型与原始文件相同特殊文件(l 类型)
# 创建硬链接
ln 原文件 硬链接名# 查看文件的硬链接数(ls 输出的第二列)
ls -l

因此,在linux环境上,可以使用硬链接来替代删除,然后通过 tar 包进行压缩,以实现节省空间的目的。

tar 可以保留硬链接关系(通过 --hard-dereference 选项控制),再结合 gzip/xz 等压缩。

tar czf archive.tar.gz --hard-dereference dir/  # 压缩时保留硬链接
tar xzf archive.tar.gz                           # 解压时恢复硬链接
http://www.lryc.cn/news/609555.html

相关文章:

  • Unix 命令行shell基础--学习系列003
  • Web 开发 12
  • 嵌入式硬件中三极管原理分析与控制详解
  • 嵌入式硬件篇---OpenMV存储
  • 单片机51 day46
  • 基于单片机智能鱼缸/水族箱/水产养殖系统设计
  • 第二篇:深入解析 FastAPI + LangChain 实现流式对话接口:`chat` 函数详解
  • 嵌入式硬件中三极管推挽电路控制与实现
  • 单片机裸机程序设计架构
  • Ubuntu 下 MySQL 运维自动化部署教程(在线简易版)
  • MLIR Introduction
  • cobalt strike(CS)与Metasploit(MSF)联动
  • Nestjs框架: @nestjs/config 配置模块详解与实践
  • Go 语言模糊测试 (Fuzz Testing) 深度解析与实践
  • 基于鼠标位置的相机缩放和平移命令的实现(原理+源码)
  • Java 17新特性深度解读:Records、Sealed Classes与Pattern Matching
  • 宝塔面板安装WordPress教程:10分钟一键部署搭建个人博客 (2025)
  • Git如何同步本地与远程仓库并解决冲突
  • Linux 用户与组管理全解析
  • 电商系统想撑住大流量?ZKmall开源商城靠微服务 + Spring Boot3 解决单体架构难题
  • JavaScript中的作用域、闭包、定时器 由浅入深
  • 肾上腺疾病AI诊疗一体化系统应用方向探析
  • 机器学习——学习路线
  • 【拓扑序 容斥原理】P6651 「SWTR-5」Chain|省选-
  • 登录验证码功能实现:Spring Boot + Vue 全流程解析
  • Ethereum:智能合约开发者的“瑞士军刀”OpenZeppelin
  • Neo4j 社区版 Mac 安装教程
  • 数据结构---配置网络步骤、单向链表额外应用
  • Vue3核心语法进阶(Hook)
  • 如何使用EF框架操作Sqlite