当前位置: 首页 > 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.dtcms.com/a/314982.html

相关文章:

  • 正则表达式全解析:从基础到实战(附 Python re 模块用法)
  • 基于知识图谱增强的RAG系统阅读笔记(二)向量相似性搜索与混合搜索
  • ESDocValues机制
  • GEM_ 迈向通用LLM智能体训练新纪元
  • Java 后端 + JavaScript 前端 实现按钮级别权限控制的解决方案
  • HTTP、WebSocket、TCP、Kafka等通讯渠道对比详解
  • JavaScript案例(乘法答题游戏)
  • Claude Code六周回顾
  • 关键字 - 第一讲
  • 【Redis】安装Redis,通用命令
  • dubbo——远程服务调用
  • 华为OD机考2025C卷 - 分配土地 (Java Python JS C++ C )
  • 解决MySQL删除/var/lib/mysql下的所有文件后无法启动的问题
  • SpringBoot基础复习
  • SwiftUI ios开发中的 MVVM 架构深度解析与最佳实践
  • 为什么ping和dig(nslookup)返回地址不一样,两者的区别
  • ElfBoard技术贴|如何在【RK3588】ELF 2开发板中安装openCV4以及第三方库contrib
  • 腾讯混元3d模型360全景模式
  • Python 桌面时钟屏保程序
  • Dynamic Programming【DP】1
  • 【Linux】gdb cgdb — 基操
  • 广东省省考备考(第六十六天8.4)——判断推理(强化训练)
  • 竞品分析爬虫实现方案
  • Adobe Experience Manager (AEM) Assets|企业级数字资产管理平台(DAM)
  • 【DAB收音机】DAB服务跟随Service Follow功能介绍(一)
  • RAG常见问题与优化方法全解析|从新手到高手的实践指南
  • 【Spring】SpringBoot 自动配置,@ComponentScan、@Import、ImportSelector接口
  • 下载 | Windows Server 2025官方原版ISO映像!(7月更新、标准版、数据中心版、26100.4652)
  • Android工程命令行打包并自动生成签名Apk
  • MySQL 8.0源码编译安装