首页 > 其他分享 >导入ZIP压缩包比较图片的hash值重复

导入ZIP压缩包比较图片的hash值重复

时间:2024-06-02 17:28:21浏览次数:22  
标签:hash String ZIP java return File new 压缩包 图片

项目中碰到需要在导入过程中和当前目录中的图片进行比较,判断是否存在相同的图片,相同则把导入的图片删除掉

该内容较多:需要仔细分析每部分代码,结合你需要内容获取对应代码 !!!!!!!!

首先把工具类导入进来:

对应hash比较工具类我是参考该作者博客:java通过哈希比较图片相似度_java中imagecompare-CSDN博客

我在当前我功能中也有做额外拓展,各位兄弟按自己需求选择使用 !!!!!!!!!

import java.awt.Graphics;
import java.awt.Image;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.util.Arrays;

/**
 * 均值哈希实现图像指纹比较
 *
 * @author
 */
public class ContrastImgUntil {

    /**
     * 图像指纹的尺寸,将图像resize到指定的尺寸,来计算哈希数组
     */
    private static final int HASH_SIZE = 16;
    /**
     * 保存图像指纹的二值化矩阵
     */
    private final byte[] binaryzationMatrix;

    public ContrastImgUntil(byte[] hashValue) {
        if (hashValue.length != HASH_SIZE * HASH_SIZE)
            throw new IllegalArgumentException(String.format("length of hashValue must be %d", HASH_SIZE * HASH_SIZE));
        this.binaryzationMatrix = hashValue;
    }

    public ContrastImgUntil(String hashValue) {
        this(toBytes(hashValue));
    }

    /**
     * 本次调用的方法,
     *
     * @param src
     */
    public ContrastImgUntil(BufferedImage src) {
        this(hashValue(src));
    }

    //
    private static byte[] hashValue(BufferedImage src) {
        BufferedImage hashImage = resize(src, HASH_SIZE, HASH_SIZE);
        byte[] matrixGray = (byte[]) toGray(hashImage).getData().getDataElements(0, 0, HASH_SIZE, HASH_SIZE, null);
        return binaryzation(matrixGray);
    }

    /**
     * 从压缩格式指纹创建{@link ContrastImgUntil}对象
     *
     * @param compactValue
     * @return
     */
    public static ContrastImgUntil createFromCompact(byte[] compactValue) {
        return new ContrastImgUntil(uncompact(compactValue));
    }

    public static boolean validHashValue(byte[] hashValue) {
        if (hashValue.length != HASH_SIZE)
            return false;
        for (byte b : hashValue) {
            if (0 != b && 1 != b) return false;
        }
        return true;
    }

    public static boolean validHashValue(String hashValue) {
        if (hashValue.length() != HASH_SIZE)
            return false;
        for (int i = 0; i < hashValue.length(); ++i) {
            if ('0' != hashValue.charAt(i) && '1' != hashValue.charAt(i)) return false;
        }
        return true;
    }

    public byte[] compact() {
        return compact(binaryzationMatrix);
    }

    /**
     * 指纹数据按位压缩
     *
     * @param hashValue
     * @return
     */
    private static byte[] compact(byte[] hashValue) {
        byte[] result = new byte[(hashValue.length + 7) >> 3];
        byte b = 0;
        for (int i = 0; i < hashValue.length; ++i) {
            if (0 == (i & 7)) {
                b = 0;
            }
            if (1 == hashValue[i]) {
                b |= 1 << (i & 7);
            } else if (hashValue[i] != 0)
                throw new IllegalArgumentException("invalid hashValue,every element must be 0 or 1");
            if (7 == (i & 7) || i == hashValue.length - 1) {
                result[i >> 3] = b;
            }
        }
        return result;
    }

    /**
     * 压缩格式的指纹解压缩
     *
     * @param compactValue
     * @return
     */
    private static byte[] uncompact(byte[] compactValue) {
        byte[] result = new byte[compactValue.length << 3];
        for (int i = 0; i < result.length; ++i) {
            if ((compactValue[i >> 3] & (1 << (i & 7))) == 0)
                result[i] = 0;
            else
                result[i] = 1;
        }
        return result;
    }

    /**
     * 字符串类型的指纹数据转为字节数组
     *
     * @param hashValue
     * @return
     */
    private static byte[] toBytes(String hashValue) {
        hashValue = hashValue.replaceAll("\\s", "");
        byte[] result = new byte[hashValue.length()];
        for (int i = 0; i < result.length; ++i) {
            char c = hashValue.charAt(i);
            if ('0' == c)
                result[i] = 0;
            else if ('1' == c)
                result[i] = 1;
            else
                throw new IllegalArgumentException("invalid hashValue String");
        }
        return result;
    }

    /**
     * 缩放图像到指定尺寸1
     *
     * @param src
     * @param width
     * @param height
     * @return
     */
    private static BufferedImage resize(Image src, int width, int height) {
        BufferedImage result = new BufferedImage(width, height,
                BufferedImage.TYPE_3BYTE_BGR);
        Graphics g = result.getGraphics();
        try {
            g.drawImage(src.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);
        } finally {
            g.dispose();
        }
        return result;
    }

    /**
     * 计算均值
     *
     * @param src
     * @return
     */
    private static int mean(byte[] src) {
        long sum = 0;
        // 将数组元素转为无符号整数
        for (byte b : src) sum += (long) b & 0xff;
        return (int) (Math.round((float) sum / src.length));
    }

    /**
     * 二值化处理1
     *
     * @param src
     * @return
     */
    private static byte[] binaryzation(byte[] src) {
        byte[] dst = src.clone();
        int mean = mean(src);
        for (int i = 0; i < dst.length; ++i) {
            // 将数组元素转为无符号整数再比较
            dst[i] = (byte) (((int) dst[i] & 0xff) >= mean ? 1 : 0);
        }
        return dst;

    }

    /**
     * 转灰度图像1
     *
     * @param src
     * @return
     */
    private static BufferedImage toGray(BufferedImage src) {
        if (src.getType() == BufferedImage.TYPE_BYTE_GRAY) {
            return src;
        } else {
            // 图像转灰
            BufferedImage grayImage = new BufferedImage(src.getWidth(), src.getHeight(),
                    BufferedImage.TYPE_BYTE_GRAY);
            new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null).filter(src, grayImage);
            return grayImage;
        }
    }

    @Override
    public String toString() {
        return toString(true);
    }

    /**
     * @param multiLine 是否分行
     * @return
     */
    public String toString(boolean multiLine) {
        StringBuffer buffer = new StringBuffer();
        int count = 0;
        for (byte b : this.binaryzationMatrix) {
            buffer.append(0 == b ? '0' : '1');
            if (multiLine && ++count % HASH_SIZE == 0)
                buffer.append('\n');
        }
        return buffer.toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof ContrastImgUntil) {
            return Arrays.equals(this.binaryzationMatrix, ((ContrastImgUntil) obj).binaryzationMatrix);
        } else
            return super.equals(obj);
    }

    /**
     * 与指定的压缩格式指纹比较相似度
     *
     * @param compactValue
     * @return
     * @see #compare(ContrastImgUntil)
     */
    public float compareCompact(byte[] compactValue) {
        return compare(createFromCompact(compactValue));
    }

    /**
     * @param hashValue
     * @return
     * @see #compare(ContrastImgUntil)
     */
    public float compare(String hashValue) {
        return compare(new ContrastImgUntil(hashValue));
    }

    /**
     * 与指定的指纹比较相似度
     *
     * @param hashValue
     * @return
     * @see #compare(ContrastImgUntil)
     */
    public float compare(byte[] hashValue) {
        return compare(new ContrastImgUntil(hashValue));
    }

    /**
     * 与指定图像比较相似度
     *
     * @param image2
     * @return
     * @see #compare(ContrastImgUntil)
     */
    public float compare(BufferedImage image2) {
        return compare(new ContrastImgUntil(image2));
    }

    /**
     * 比较指纹相似度
     *
     * @param src
     * @return
     * @see #compare(byte[], byte[])
     */
    public float compare(ContrastImgUntil src) {
        if (src.binaryzationMatrix.length != this.binaryzationMatrix.length)
            throw new IllegalArgumentException("length of hashValue is mismatch");
        return compare(binaryzationMatrix, src.binaryzationMatrix);
    }

    /**
     * 判断两个数组相似度,数组长度必须一致否则抛出异常
     *
     * @param f1
     * @param f2
     * @return 返回相似度(0.0 ~ 1.0)
     */
    private static float compare(byte[] f1, byte[] f2) {
        if (f1.length != f2.length)
            throw new IllegalArgumentException("mismatch ContrastImgUntil length");
        int sameCount = 0;
        for (int i = 0; i < f1.length; ++i) {
            if (f1[i] == f2[i]) ++sameCount;
        }
        return (float) sameCount / f1.length;
    }

    public static float compareCompact(byte[] f1, byte[] f2) {
        return compare(uncompact(f1), uncompact(f2));
    }

    public static float compare(BufferedImage image1, BufferedImage image2) {
        return new ContrastImgUntil(image1).compare(new ContrastImgUntil(image2));
    }

    //返回当前图片的哈希值
    public String getHashAsString() {
        StringBuilder hashStringBuilder = new StringBuilder();
        for (byte b : binaryzationMatrix) {
            hashStringBuilder.append(b == 0 ? '0' : '1');
        }
        return hashStringBuilder.toString();
    }
}

主要逻辑代码如下:(为了方便解读,后面会具体说明方法的使用解析)

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yr.common.util.*;
import com.yr.dataAnnotations.config.ResourceAccessProperties;
import com.yr.dataAnnotations.config.SpringBootPlusProperties;
import com.yr.dataAnnotations.entity.*;
import com.yr.dataAnnotations.mapper.*;
import com.yr.dataAnnotations.param.*;
import com.yr.dataAnnotations.service.*;
import com.yr.dataAnnotations.util.CmdUtil;
import com.yr.dataAnnotations.util.ContrastImgUntil;
import com.yr.dataAnnotations.vo.*;
import com.yr.newframe.core.common.exception.BusinessException;
import com.yr.newframe.core.common.service.impl.BaseServiceImpl;
import com.yr.newframe.core.config.properties.FrameProperties;
import com.yr.newframe.core.context.UserContext;
import com.yr.newframe.core.core.pagination.PageInfo;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yr.newframe.core.core.util.RedisFrameUtil;
import com.yr.newframe.core.util.UUIDUtil;
import org.apache.commons.io.FileUtils;
import org.springframework.transaction.annotation.Transactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;

import java.awt.image.BufferedImage;
import java.io.*;
import java.io.File;
import java.nio.charset.Charset;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

//added by lhh
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
@Service
public class FileServiceImpl extends BaseServiceImpl<FileMapper, File> implements FileService {

    // SIMILARITY_THRESHOLD 定义相似度阈值,例如1表示至少100%相似度才认为图片相同
    private static final float SIMILARITY_THRESHOLD = 1f;

    /**
     * 文件分片上传处理
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    public Map<String, String> uploadFile(HttpServletRequest request, HttpServletResponse response) throws Exception {
        Map<String, String> map = new HashMap<>();
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;

        MultipartFile multipartFile = multipartRequest.getFile("file");                                                 //获得文件分片数据
        String uuid = multipartRequest.getParameter("uuid");                                                            //前端uuid,作为标识
        int total = Integer.parseInt(multipartRequest.getParameter("totalChunks"));                                     //总片数
        int index = Integer.parseInt(multipartRequest.getParameter("chunkNumber"));                                     //分片第几片
        String fileName = multipartRequest.getParameter("filename").replaceAll(" ", "");            //获取文件名
        String fileType = multipartRequest.getParameter("fileType");                                                    //文件类型:.图片文件
        String catalogId = multipartRequest.getParameter("catalogId");                                                  //文件类型,传图片文件目录id
        String name = fileName.replace(".zip", "").replaceAll(".tar", "").replace(".gz", "");

        if (StrUtil.isBlank(fileType) || StrUtil.equals(fileType, "1")) {
            if (StrUtil.isBlank(catalogId)) {
                throw new BusinessException("图片文件目录id不能为空!");
            }

            /** 目录是否关联任务;是:不允许导入图,反之导入 */
            QueryWrapper<TaskCatalog> taskCatalogQW = new QueryWrapper<>();
            taskCatalogQW.eq("catalog_id", catalogId);
            int count = taskCatalogService.count(taskCatalogQW);
            if (count > 0) {
                throw new BusinessException("该目录已关联任务,不能导入图片!");
            }
        } else {
            throw new BusinessException("文件类型不存在!");
        }
        //本地测试可启用
//        String uploadPath = "D:\\Desktop\\imageTestFile" + java.io.File.separator + CmdUtil.FOLDER_NAME_2 + uuid;//(本地测试)
        String uploadPath = springBootPlusProperties.getUploadPath() + CmdUtil.FOLDER_NAME_2 + uuid;
        String newName = DateUtil.ymdHms.format(new Date()) + "_" + name + "_" + index + ".tem";
        java.io.File uploadFile = new java.io.File(uploadPath, newName);
        if (!uploadFile.getParentFile().exists()) {
            uploadFile.getParentFile().mkdirs();
        }
        try {
            if (index < total) {
                //表示当前分片文件上传成功
                multipartFile.transferTo(uploadFile);
                map.put("status", "201");
            } else {
                //表示全部分片文件上传成功
                multipartFile.transferTo(uploadFile);
                map.put("status", "200");
                map.put("uuid", uuid);
                map.put("fileName", fileName);
                map.put("catalogId", catalogId);
                map.put("fileType", fileType);
                map.put("id", id);
                System.out.println("上传分片文件总数:--------" + total);
            }
            System.out.println("上传分片文件存储路径:--------" + uploadPath);
        } catch (IOException e) {
            //分片文件上传失败
            e.printStackTrace();
            map.put("status", "502");
        }
        return map;
    }


    /**
     * 合并文件处理方法
     * @param fileMergeParam
     * @param userId
     * @return
     * @throws Exception
     */
    public Map<String, String> mergeNewProject(FileMergeParam fileMergeParam, String userId) throws Exception {
        String uuid = fileMergeParam.getUuid();
        String fileName = fileMergeParam.getFileName();
        String fileType = fileMergeParam.getFileType();    //文件类型:1.图片文件
        String catalogId = fileMergeParam.getCatalogId();  //文件类型为1时,传图片文件目录iD
        AlgorithmType algorithmTypeInfo = null;

        Map<String, String> map = new HashMap<>();//返回异常
//        String uploadPath ="D:\\Desktop\\imageTestFile\\";//(本地测试,修改成本地的文件夹路径)
        /** 根路径 */
        String uploadPath = springBootPlusProperties.getUploadPath();
        /** 压缩包绝对路径;例如:/xxxx/xxxxm/upload/xxx.zip */
        java.io.File targetFile;
        /** 压缩包名称 */
        String name;

        try {
            /** 压缩包存储的目录地址 */
            String newUploadPath;

            //缓存的临时分片文件夹
            String tempPath = uploadPath + CmdUtil.FOLDER_NAME_2 + uuid;
            System.out.println("--------开始分片文件合并--------:" + tempPath);
            java.io.File dirFile = new java.io.File(tempPath);
            if (!dirFile.exists()) {
                throw new BusinessException("文件不存在!");
            }

            /** 分片上传的文件已经位于同一个文件夹下,方便寻找和遍历(当文件数大于十的时候记得排序,确保顺序是正确的)*/
            java.io.File[] files = dirFile.listFiles();
            List<java.io.File> fileList = FileUtil.fileSort(files);

            if (StrUtil.isBlank(fileType) || StrUtil.equals(fileType, "1")) {
                //创建空的合并文件目录
                newUploadPath = uploadPath + CmdUtil.FOLDER_NAME_2 + CmdUtil.FOLDER_NAME_3;
                name = DateUtil.ymdHms.format(new Date()) + "_" + fileName.replaceAll(" ", "");
                targetFile = new java.io.File(newUploadPath, name);
                if (!targetFile.getParentFile().exists()) {
                    targetFile.getParentFile().mkdirs();
                }
            } else {
                throw new BusinessException("文件类型不存在!");
            }
            System.out.println("合并文件存储路径:--------" + targetFile.getPath());
            RandomAccessFile writeFile = new RandomAccessFile(targetFile, "rw");

            long position = 0;
            for (java.io.File file : fileList) {
                //每个分片文件的具体路径
                RandomAccessFile readFile = new RandomAccessFile(file, "rw");
                int chunkSize = 1024 * 3;
                byte[] buf = new byte[chunkSize];
                writeFile.seek(position);

                int byteCount;
                while ((byteCount = readFile.read(buf)) != -1) {
                    if (byteCount != chunkSize) {
                        byte[] tempBytes = new byte[byteCount];
                        System.arraycopy(buf, 0, tempBytes, 0, byteCount);
                        buf = tempBytes;
                    }
                    writeFile.write(buf);
                    position = position + byteCount;
                }

                readFile.close();
                //删除缓存的临时分片文件(本地测试时,需要注释改代码)
                FileUtils.deleteQuietly(file);
            }
            writeFile.close();
            //清除缓存的临时分片文件夹(本地测试时,需要注释改代码)
            FileUtils.deleteQuietly(dirFile);
        } catch (Exception e) {
            e.printStackTrace();
            map.put("status", "502");
            map.put("tipMess", "导入失败!");
            return map;
        }
        System.out.println("--------分片文件合并完成--------");

        if (StrUtil.isBlank(fileType) || StrUtil.equals(fileType, "1")) {
            /** 图片压缩文件 */
            String imageMess = fileNewProjectDispose(targetFile.getPath(), catalogId, StrUtil.isBlank(userId) ? "admin" : userId);
            map.put("imageMessage", imageMess);
            map.put("status", "200");
            map.put("tipMess", "导入成功!");
        } else {
            throw new BusinessException("文件类型不存在!");
        }
        return map;
    }

    /**
     * 解压处理图片比较逻辑
     * @param path
     * @param catalogId
     * @param userId
     * @return
     */
    private String fileNewProjectDispose(String path, String catalogId, String userId) {
        String resuletMess = "";
        /** 获取目录地址 */
        Catalog catalogInfo = catalogService.getById(catalogId);
        if (catalogInfo == null) {
            throw new BusinessException("目录不存在!");
        }

        /** 获取该目录下的所有文件,并转成Map用于下面的校验 */
        Map<String, File> mapFileInfo = new HashMap<>();
        QueryWrapper<File> fileQueryWrapper = new QueryWrapper<>();
        fileQueryWrapper.eq("catalog_id", catalogId);
        List<File> fileList = super.list(fileQueryWrapper);
        if (fileList.size() > 0) {
            for (File vo : fileList) {
                String name = vo.getFileName();
                if (mapFileInfo.containsKey(name)) {
                    continue;
                }
                mapFileInfo.put(name, vo);
                mapFileInfo.put(name.substring(0, name.lastIndexOf(".") + 1) + "xml", vo);
            }
        }

        System.out.println("--------开始压缩包解压-------- HT1");

        java.io.File filePath = new java.io.File(path);
        String folderName = filePath.getName().substring(0, filePath.getName().indexOf("."));
        //解压后的地址
        String tagert = springBootPlusProperties.getUploadPath() + CmdUtil.FOLDER_NAME_2 + CmdUtil.FOLDER_NAME_3 + folderName + java.io.File.separator;
//        String tagert = "D:\\Desktop\\imageTestFile\\img"; //(本地测试)先默认写到本地
        java.io.File targertFile = new java.io.File(tagert);
        if (!targertFile.exists()) {
            targertFile.mkdirs();
        }

        String deCompressedAddress = ""; //解压后图片存放的路径
        try {
            /** 解压上传的文件 */
            deCompressedAddress = unZip(path, tagert);
            System.out.println("解压地址----------HT4_XIAN_ZAI_JIE_YA_HOU_DE" + tagert);
        } catch (IOException e) {
            System.out.println("文件解压失败----------" + e.getMessage());
            throw new BusinessException("文件解压失败!");
        }
        System.out.println("解压地址----------HT5_YUAN_DI_ZI" + tagert);

        /** 原数据库存储图片数据、hash值集合  格式: image.jpg,hash值 */
        Map<String, String> imageHash = new HashMap<>();
        /** 最新解压导入文件图片数据、hash值集合  格式: image.jpg,hash值 */
        Map<String, String> importImgHashValue = new HashMap<>();
        try {
            /**
             * 获取出当前目录下的所有图片地址信息
             */
            QueryWrapper<File> queryFileWrapper = new QueryWrapper<>();
            queryFileWrapper.eq("catalog_id", catalogId);
            List<File> filesData = super.list(queryFileWrapper);

            Long catalogInfoId = catalogInfo.getId(); //获取目录id

            for (File filesDatum : filesData) {
                //图片地址实例:/huidate/hui_ware/data/kistm/file/images/upload/catalog/XX/image.jpg
                String imageFile = springBootPlusProperties.getUploadPath() + "catalog" + java.io.File.separator +
                        catalogInfoId + java.io.File.separator + filesDatum.getFileName();
                String hashValue = filesDatum.getHashValue();//导入图片的hash值
                imageHash.put(filesDatum.getFileName(), hashValue);
            }

            System.out.println("原数据图片Map集合内容(DatabasImageMap):" + imageHash);

            /** 解压上传的文件拿到解压出来的图片信息*/
            List<String> targetPathList = unZipAndGetImagePaths(path, tagert);

            /**
             * 计算获取出所有导入图片的hash值
             * Map集合格式为:<图片名称,hash值>
             */
            importImgHashValue = getImportImgHashValue(targetPathList);

            if (!imageHash.isEmpty()) {
                /** 根据导入图片的hash值和原图片hash值做对比 */
                DuplicateResult duplicateResult = compareImagesWithBaseline(imageHash, importImgHashValue);
                //重复图片数量
                int duplicatesCount = duplicateResult.getDuplicatesCount();
                //重复图片集合
                List<String> allDuplicates = duplicateResult.getAllDuplicates();

                // 如果所有图片都是重复的,则直接返回提示信息,无需进一步处理
                if (duplicatesCount == importImgHashValue.size()) {
                    String tipMessError = "所有导入的数据均为重复数据,已停止处理!";
                    resuletMess = tipMessError;
                    return resuletMess; // 这里结束方法的执行
                }
                //返回的提示
                if (duplicatesCount > 0) {
                    String tipMessError = "当前导入数据存在:" + duplicatesCount + "张重复数据,保留原始数据,重复数据已剔除!";
                    resuletMess = tipMessError;
                }
                /**
                 * 遍历取出重复图片名称,找到解压文件夹,执行删除操作
                 * deCompressedAddress 解压后的文件路径
                 */
                Path deCompressDir = Paths.get(deCompressedAddress);
                try (DirectoryStream<Path> stream = Files.newDirectoryStream(deCompressDir)) {
                    // 将解压目录下的文件路径与重复图片名称列表比对,执行删除操作
                    for (Path fileRemovePath : stream) {
                        for (String imageName : allDuplicates) {
                            if (fileRemovePath.getFileName().toString().equals(imageName)) {
                                // 找到了同名文件,执行删除操作
                                Files.delete(fileRemovePath);
                                System.out.println("Deleted: " + fileRemovePath);
                                break; // 删除后跳出当前图片名称的内层循环,避免重复处理
                            }
                        }
                    }
                } catch (IOException e) {
                    System.err.println("删除文件时发生错误: " + e.getMessage());
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }


        /** 目录下所有文件(包含子级下文件)路径集合,格式:<文件夹(目录)名称,<文件名称,文件路径集合>> */
        Map<String, Map<String, List<String>>> filePathMap = new HashMap<>();
        /**
         * 拿解压后的目录地址,进行写入图片内容到数据库
         */
        java.io.File file = new java.io.File(deCompressedAddress);
        FileUtil.findFileList(file, filePathMap);

        /** 文件信息存储对象集合 */
        List<File> fileInfoList = new ArrayList<>();

        String cpCmd;
        String mvCmd;
        if (CmdUtil.checkSystem()) {
            //Windows命令
            cpCmd = CmdUtil.WINDOWS_COPY;
            mvCmd = CmdUtil.WINDOWS_MOVE;
        } else {
            //Linux命令
            cpCmd = CmdUtil.LINUX_COPY;
            mvCmd = CmdUtil.LINUX_MOVE;
        }

        //解析出图片信息,进行写表操作
        Iterator<Map.Entry<String, Map<String, List<String>>>> it = filePathMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Map<String, List<String>>> catalogEntry = it.next();
            String catalogKey = catalogEntry.getKey();
            Map<String, List<String>> catalogValue = catalogEntry.getValue();

            Iterator<Map.Entry<String, List<String>>> itt = catalogValue.entrySet().iterator();
            while (itt.hasNext()) {
                /** 文件信息存储对象 */
                File fileInfo = new File();
                fileInfo.setCatalogId(catalogInfo.getId() + "");
                fileInfo.setRevision(0);
                fileInfo.setCreatedBy(userId);
                fileInfo.setCreatedTime(new Date());
                fileInfo.setUpdatedBy(userId);
                fileInfo.setUpdatedTime(new Date());


                int labelNum = 0;
                boolean isPic = false;
                String hms = DateUtil.hms.format(new Date());

                Map.Entry<String, List<String>> entry = itt.next();
                String key = entry.getKey();
                List<String> filePathList = entry.getValue();

                /**
                 *  遍历出新解压导入文件图片数据、hash值集合,写入图片的hash到当前数据上
                 */
                importImgHashValue.forEach((imgKey, value) -> {
                    // 假设文件名是键的一部分,去除扩展名 ".jpg"
                    String fileNameWithoutExt = imgKey.substring(0, imgKey.length() - 4);
                    if (key.equals(fileNameWithoutExt)) {
                        fileInfo.setHashValue(value);
                    }
                });

                for (String str : filePathList) {
                    java.io.File fileStr = new java.io.File(str);
                    String fileName = fileStr.getName().replaceAll(" ", "");
                    String name = fileName.substring(0, fileName.indexOf("."));
                    String suffix = fileName.substring(fileName.indexOf("."));

                    /** 是否有图片,有则保存数据反之跳过 */
                    if (filePathList.size() > 1 || ImageUtil.isPic2(suffix)) {
                        /** 图片或xml文件是否已存在,存在则重命名 */
                        if (mapFileInfo.containsKey(fileName)) {
                            name += "-副本" + hms;
                            fileName = name + suffix;

                            String parentFilePath = fileStr.getParentFile().getPath() + java.io.File.separator + fileName;
                            java.io.File newFileStr = new java.io.File(parentFilePath);
                            if (!fileStr.renameTo(newFileStr)) {
                                throw new BusinessException("图片或xml文件重命名失败!");
                            }
                            fileStr = newFileStr;
                        }

                        if (ImageUtil.isPic2(suffix)) {
                            System.out.println("--------开始图片解析--------");
                            /** 是图片:1.进行图片解析并获取宽高、拍摄时间。2.生成图片缩略图,并存储 */
                            fileInfo.setFileName(fileName);
                            try {
                                Map<String, Object> imgInfo = ImageUtil.getImgInfo(fileStr);
                                fileInfo.setWidth((Integer) imgInfo.get("imageWidth"));
                                fileInfo.setHeigth((Integer) imgInfo.get("imageHeight"));
                                fileInfo.setFileTime(DateUtil.StrToShortDate(imgInfo.get("shootTime") + ""));
                            } catch (Exception e) {
                                System.out.println("图片解析失败---------:" + e.getMessage());
                                throw new BusinessException("图片解析失败!");
                            }

                            String imgThumbPath = springBootPlusProperties.getUploadPath() + CmdUtil.FOLDER_NAME_4 + catalogId + java.io.File.separator + name + "_thumb" + suffix;
                            //本地测试可先注释
//                            String imgThumbPath = " D:\\Desktop\\imageTestFile\\" + CmdUtil.FOLDER_NAME_4 + catalogId + java.io.File.separator + name + "_thumb" + suffix;


                            java.io.File newFile = new java.io.File(imgThumbPath);
                            if (!newFile.getParentFile().exists()) {
                                newFile.getParentFile().mkdirs();
                            }
                            String copyThumbCommand = cpCmd + " " + fileStr + " " + imgThumbPath;
                            if (!CmdUtil.sendInstructions(copyThumbCommand)) {
                                throw new BusinessException("缩略图归类失败!");
                            }
                            //本地测试可先注释
                            if (!ImageUtil.createThumbnail(imgThumbPath, 400, 400)) {
                                throw new BusinessException("缩略图生成失败!");
                            }
                            fileInfo.setThumb(imgThumbPath);
                            isPic = true;
                        } else if (StrUtil.equals(suffix, ".xml")) {
                            System.out.println("--------开始xml解析--------");
                            /** 是xml文件:进行xml解析并获取内容 */
                            try {
                                Map<String, Object> xmlMap = FileUtil.analysisXML(fileStr);
                                labelNum = (int) xmlMap.get("labelNum");
                                fileInfo.setLabelNames(xmlMap.get("name") + "");
                                fileInfo.setHashValue(xmlMap.get("hashValue") + "");
                                fileInfo.setXmlContent(JSON.toJSONString(xmlMap.get("bndbox")));
                            } catch (Exception e) {
                                System.out.println("xml解析失败---------:" + e.getMessage());
                                throw new BusinessException("xml解析失败!");
                            }
                        } else {
                            continue;
                        }
                        fileInfo.setLabelNum(labelNum);

                        /** 使用Linux命令,将图片和xml移动到相应的目录下 */
                        String copyCommand = mvCmd + " " + fileStr + " " + catalogInfo.getFilepath();
                        if (!CmdUtil.sendInstructions(copyCommand)) {
                            throw new BusinessException("文件归类失败!");
                        }
                        System.out.println("--------文件归类成功--------");
                    }
                }

                /** 是否有图片,有则保存数据反之跳过 */
                if (!isPic) {
                    continue;
                }

                String names = fileInfo.getFileName();
                if (!mapFileInfo.containsKey(names)) {
                    mapFileInfo.put(names, fileInfo);
                    mapFileInfo.put(names.substring(0, names.lastIndexOf(".") + 1) + "xml", fileInfo);
                }
                fileInfoList.add(fileInfo);
            }
        }

        if (fileInfoList.size() <= 0) {
            throw new BusinessException("该压缩包没有文件!");
        }
        boolean stateBy = super.saveBatch(fileInfoList);
        if (!stateBy) {
            resuletMess += "保存导入图片失败!请联系管理员!";
        }

        return resuletMess;
    }

    /**
     * 解压zip文件
     *
     * @param zipfile 文件地址 D:\\upload\\解压\\a.zip
     * @param tagert  解压目的地址 D:\\upload\\解压\\
     * @throws IOException
     */
    public String unZip(String zipfile, String tagert) throws IOException {
        try {
            long startTime = System.currentTimeMillis();
            File zfile = new File(zipfile);
            FileInputStream fis = new FileInputStream(zfile);
            String code = "UTF-8";
            try {
                code = resolveCode(zipfile);
            } catch (Exception e) {
                e.printStackTrace();
            }

            //默认UTF-8
            Charset charset = Charset.forName(code);
            // 输入源zip路径
            ZipInputStream zis = new ZipInputStream(fis, charset);
            ZipEntry entry = null;
            File file = new File(tagert);
            if (!file.exists()) {
                file.mkdir();
            }
            String s = null;
            BufferedOutputStream bos = null;
            while ((entry = zis.getNextEntry()) != null) {
                /** 去除文件名的空格和括号 */
                String name = entry.getName().replaceAll("\\s*", "").replaceAll("\\(", "").replaceAll("\\)", "");

                if (entry.isDirectory()) {
                    File filePath = new File(tagert + name);
                    //如果目录不存在,则创建
                    if (!filePath.exists()) {
                        filePath.mkdirs();
                    }
                } else {
                    //当压缩包中包含目录时,程序会当成文件执行,所以添加下面代码进行控制
                    if (String.valueOf(entry).contains("/")) {
                        String s1 = name.substring(0, name.lastIndexOf("/"));
                        String s2 = name.substring(name.lastIndexOf("/") + 1);

                        File filePath = new File(tagert + s1 + File.separator);
                        if (!filePath.exists()) {
                            filePath.mkdir();
                        }
                        s = s1 + File.separator;
                        name = s1 + File.separator + s2;
                    }

                    System.err.println(tagert + name.trim());
                    FileOutputStream fos = new FileOutputStream(tagert + name.trim());
                    bos = new BufferedOutputStream(fos);
                    byte buf[] = new byte[1024];
                    int len;
                    while ((len = zis.read(buf)) != -1) {
                        bos.write(buf, 0, len);
                    }
                    zis.closeEntry();
                    //关闭的时候会刷新
                    bos.close();
                }
            }
            //当压缩包存在下级目录时
            if (StrUtil.isNotBlank(s)) {
                tagert += s;
            }
            zis.close();
            long endTime = System.currentTimeMillis();
            System.out.println("解压完成!所需时间为:" + (endTime - startTime) + "ms");
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
        return tagert;
    }

    /**
     * 拿到解压出来的图片信息
     *
     * @param zipfile
     * @param target
     * @return
     * @throws IOException
     */
    public List<String> unZipAndGetImagePaths(String zipfile, String target) throws IOException {
        String resultPath = ZipUtil.unZip(zipfile, target); // 先调用原有解压方法
        if (resultPath.isEmpty()) {
            System.err.println("解压失败,无法获取图片数据");
            return new ArrayList<>(); // 返回一个空列表
        }

        java.io.File targetFolder = new java.io.File(resultPath);
        // 遍历解压目录,查找图片文件,并收集图片路径
        List<String> imagePaths = new ArrayList<>();
        if (targetFolder.exists() && targetFolder.isDirectory()) {
            java.io.File[] files = targetFolder.listFiles((dir, name) -> {
                String lowercaseName = name.toLowerCase();
                for (String extension : new String[]{"jpg", "jpeg", "png", "gif", "bmp"}) {
                    if (lowercaseName.endsWith("." + extension)) {
                        return true;
                    }
                }
                return false;
            });

            if (files != null) {
                System.out.println("找到的图片文件如下:");
                for (java.io.File imageFile : files) {
                    // 收集图片的绝对路径
                    String imagePath = imageFile.getAbsolutePath();
                    imagePaths.add(imagePath);
                    // 这里只是打印文件名和大小作为示例,你可以根据需要处理这些图片数据
                    System.out.println("图片名: " + imageFile.getName() + ", 大小: " + Files.size(imageFile.toPath()) + " bytes");
                }
            } else {
                System.out.println("解压目录下没有找到图片文件");
            }
        } else {
            System.err.println("目标路径不存在或不是一个目录");
        }
        return imagePaths;
    }

    /**
     * 根据导入的图片,生成对应的图片hash值
     *
     * @param targetPathList
     */
    private Map<String, String> getImportImgHashValue(List<String> targetPathList) {
        // 存储结果的Map
        Map<String, String> imageHashMap = new HashMap<>();

        try {
            for (String imagePath : targetPathList) {
                // 从路径中提取图片名称
                String imageName = new java.io.File(imagePath).getName();

                try {
                    // 读取图片
                    BufferedImage image = ImageIO.read(new java.io.File(imagePath));

                    // 计算哈希值
                    ContrastImgUntil contrastImgUtil = new ContrastImgUntil(image);
                    String hashString = contrastImgUtil.getHashAsString(); // 假设这个方法已正确实现

                    // 将图片名与哈希值存入Map
                    imageHashMap.put(imageName, hashString);
                } catch (IOException e) {
                    System.err.println("Error reading or processing image: " + imagePath);
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 打印结果Map
        for (Map.Entry<String, String> entry : imageHashMap.entrySet()) {
            System.out.println("Image Name: " + entry.getKey() + ", Hash Value: " + entry.getValue());
        }
        return imageHashMap;
    }


    /**
     * 根据哈希值比较图片是否相同
     *
     * @param baseImageHashes 原数据库图片的哈希值集合,键为图片名,值为哈希值
     * @param imageHashes 待比较图片的哈希值集合,键为图片名,值为哈希值(最新解压导入文件图片数据、hash值集合)
     */
    public  DuplicateResult compareImagesWithBaseline(Map<String, String> baseImageHashes, Map<String, String> imageHashes) {
        if (baseImageHashes == null || imageHashes == null) {
            throw new IllegalArgumentException("图片哈希值集合不能为空");
        }

        int duplicateCount = 0;
        List<String> duplicates = new ArrayList<>();

        // 遍历待比较图片的哈希值集合
        for (Map.Entry<String, String> entry : imageHashes.entrySet()) {
            String imageName = entry.getKey();
            String imageHash = entry.getValue();

            // 在原数据库图片哈希值集合中查找是否有相同的哈希值
            if (baseImageHashes.containsValue(imageHash)) {
                duplicates.add(imageName);
                duplicateCount++;
            }
        }

        return new DuplicateResult(duplicateCount, duplicates);
    }

/**
 * 根据hash比较图片是否相同
 *
 * @param  baseImagePaths   原数据库图片数据
 * @param  imagePaths 导人解压出来的图片数据
 */
//    public DuplicateResult compareImagesWithBaseline(List<String> baseImagePaths, List<String> imagePaths) {
//        if (baseImagePaths == null || imagePaths == null) {
//            throw new IllegalArgumentException("图片路径集合不能为空");
//        }
//        Map<String, List<String>> duplicatesMap = new HashMap<>(); // 使用Map存储重复图片路径
//        int duplicateCount = 0; // 引入计数器变量
//
//        // 对于每一张导入的图片,与原图集合中的所有图片进行比较
//        for (String baseImagePath : baseImagePaths) {
//            try {
//                BufferedImage baseImage = ImageIO.read(new java.io.File(baseImagePath));
//                ContrastImgUntil baseComparator = new ContrastImgUntil(baseImage);
//
//                for (String imagePath : imagePaths) {
//                    try {
//                        BufferedImage imgToCompare = ImageIO.read(new java.io.File(imagePath));
//                        ContrastImgUntil comparator = new ContrastImgUntil(imgToCompare);
//
//                        float similarity = baseComparator.compare(comparator);
//
//                        // 处理相似度结果
//                        if (similarity == SIMILARITY_THRESHOLD) {
//                            // 注意这里交换了basePath和imagePath的位置以更准确地反映哪两张图片重复
//                            String errorMsg = String.format("导入图片 '%s' 与原图 '%s' 相似度为100%%,存在重复!", imagePath, baseImagePath);
//                            System.err.println(errorMsg + "分隔符!!!");
//                            duplicateCount++; // 每发现一次重复就增加计数
//                            duplicatesMap.computeIfAbsent(baseImagePath, k -> new ArrayList<>()).add(imagePath);
//                        }
//                    } catch (IOException e) {
//                        e.printStackTrace(); // 处理解码图片时可能发生的异常
//                    } catch (Exception ice) {
//                        System.err.println(ice.getMessage());
//                    }
//                }
//            } catch (IOException e) {
//                e.printStackTrace(); // 处理解码图片时可能发生的异常
//            } catch (Exception ice) {
//                System.err.println(ice.getMessage());
//            }
//        }
//        // 将所有重复图片路径合并到一个列表中
//        List<String> allDuplicates = new ArrayList<>();
//        for (List<String> group : duplicatesMap.values()) {
//            allDuplicates.addAll(group);
//        }
//
//        // 返回重复图片的数量和重复图片
//        return new DuplicateResult(duplicateCount, allDuplicates);
//    }

解压方法解读:


    /**
     * 解压zip文件
     *
     * @param zipfile 文件地址 D:\\upload\\解压\\a.zip
     * @param tagert  解压目的地址 D:\\upload\\解压\\
     * @throws IOException
     */
    public String unZip(String zipfile, String tagert) throws IOException {
        try {
            long startTime = System.currentTimeMillis();
            File zfile = new File(zipfile);
            FileInputStream fis = new FileInputStream(zfile);
            String code = "UTF-8";
            try {
                code = resolveCode(zipfile);
            } catch (Exception e) {
                e.printStackTrace();
            }

            //默认UTF-8
            Charset charset = Charset.forName(code);
            // 输入源zip路径
            ZipInputStream zis = new ZipInputStream(fis, charset);
            ZipEntry entry = null;
            File file = new File(tagert);
            if (!file.exists()) {
                file.mkdir();
            }
            String s = null;
            BufferedOutputStream bos = null;
            while ((entry = zis.getNextEntry()) != null) {
                /** 去除文件名的空格和括号 */
                String name = entry.getName().replaceAll("\\s*", "").replaceAll("\\(", "").replaceAll("\\)", "");

                if (entry.isDirectory()) {
                    File filePath = new File(tagert + name);
                    //如果目录不存在,则创建
                    if (!filePath.exists()) {
                        filePath.mkdirs();
                    }
                } else {
                    //当压缩包中包含目录时,程序会当成文件执行,所以添加下面代码进行控制
                    if (String.valueOf(entry).contains("/")) {
                        String s1 = name.substring(0, name.lastIndexOf("/"));
                        String s2 = name.substring(name.lastIndexOf("/") + 1);

                        File filePath = new File(tagert + s1 + File.separator);
                        if (!filePath.exists()) {
                            filePath.mkdir();
                        }
                        s = s1 + File.separator;
                        name = s1 + File.separator + s2;
                    }

                    System.err.println(tagert + name.trim());
                    FileOutputStream fos = new FileOutputStream(tagert + name.trim());
                    bos = new BufferedOutputStream(fos);
                    byte buf[] = new byte[1024];
                    int len;
                    while ((len = zis.read(buf)) != -1) {
                        bos.write(buf, 0, len);
                    }
                    zis.closeEntry();
                    //关闭的时候会刷新
                    bos.close();
                }
            }
            //当压缩包存在下级目录时
            if (StrUtil.isNotBlank(s)) {
                tagert += s;
            }
            zis.close();
            long endTime = System.currentTimeMillis();
            System.out.println("解压完成!所需时间为:" + (endTime - startTime) + "ms");
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
        return tagert;
    }

获取解压后的压缩包所有文件信息方法:

  /**
     * 拿到解压出来的图片信息
     *
     * @param zipfile
     * @param target
     * @return
     * @throws IOException
     */
    public List<String> unZipAndGetImagePaths(String zipfile, String target) throws IOException {
        String resultPath = ZipUtil.unZip(zipfile, target); // 先调用原有解压方法
        if (resultPath.isEmpty()) {
            System.err.println("解压失败,无法获取图片数据");
            return new ArrayList<>(); // 返回一个空列表
        }

        java.io.File targetFolder = new java.io.File(resultPath);
        // 遍历解压目录,查找图片文件,并收集图片路径
        List<String> imagePaths = new ArrayList<>();
        if (targetFolder.exists() && targetFolder.isDirectory()) {
            java.io.File[] files = targetFolder.listFiles((dir, name) -> {
                String lowercaseName = name.toLowerCase();
                for (String extension : new String[]{"jpg", "jpeg", "png", "gif", "bmp"}) {
                    if (lowercaseName.endsWith("." + extension)) {
                        return true;
                    }
                }
                return false;
            });

            if (files != null) {
                System.out.println("找到的图片文件如下:");
                for (java.io.File imageFile : files) {
                    // 收集图片的绝对路径
                    String imagePath = imageFile.getAbsolutePath();
                    imagePaths.add(imagePath);
                    // 这里只是打印文件名和大小作为示例,你可以根据需要处理这些图片数据
                    System.out.println("图片名: " + imageFile.getName() + ", 大小: " + Files.size(imageFile.toPath()) + " bytes");
                }
            } else {
                System.out.println("解压目录下没有找到图片文件");
            }
        } else {
            System.err.println("目标路径不存在或不是一个目录");
        }
        return imagePaths;
    }

 
生成对应导入图片的hash值方法:

 /**
     * 根据导入的图片,生成对应的图片hash值
     *
     * @param targetPathList
     */
    private Map<String, String> getImportImgHashValue(List<String> targetPathList) {
        // 存储结果的Map
        Map<String, String> imageHashMap = new HashMap<>();

        try {
            for (String imagePath : targetPathList) {
                // 从路径中提取图片名称
                String imageName = new java.io.File(imagePath).getName();

                try {
                    // 读取图片
                    BufferedImage image = ImageIO.read(new java.io.File(imagePath));

                    // 计算哈希值
                    ContrastImgUntil contrastImgUtil = new ContrastImgUntil(image);
                    String hashString = contrastImgUtil.getHashAsString(); // 假设这个方法已正确实现

                    // 将图片名与哈希值存入Map
                    imageHashMap.put(imageName, hashString);
                } catch (IOException e) {
                    System.err.println("Error reading or processing image: " + imagePath);
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 打印结果Map
        for (Map.Entry<String, String> entry : imageHashMap.entrySet()) {
            System.out.println("Image Name: " + entry.getKey() + ", Hash Value: " + entry.getValue());
        }
        return imageHashMap;
    }

 设置DuplicateResult 返回对象类: 

import lombok.Data;

import java.util.List;

@Data
public class DuplicateResult {
    private int duplicatesCount;
    private List<String> allDuplicates;

    public DuplicateResult(int duplicatesCount, List<String> allDuplicates) {
        this.duplicatesCount = duplicatesCount;
        this.allDuplicates = allDuplicates;
    }
}

hash比较图片是否相同的两种方法:

1.直接获取当前目录下的所有图片信息,该数据会存对应的hash值,第一种方式就是拿出来直接比较效率高点

2.较为笨重、效率低(不推荐),导入的图片和原数据库图片进行比较,两个都要先转换为hash值再比较

 /**
     * 根据哈希值比较图片是否相同
     *
     * @param baseImageHashes 原数据库图片的哈希值集合,键为图片名,值为哈希值
     * @param imageHashes 待比较图片的哈希值集合,键为图片名,值为哈希值(最新解压导入文件图片数据、hash值集合)
     */
    public  DuplicateResult compareImagesWithBaseline(Map<String, String> baseImageHashes, Map<String, String> imageHashes) {
        if (baseImageHashes == null || imageHashes == null) {
            throw new IllegalArgumentException("图片哈希值集合不能为空");
        }

        int duplicateCount = 0;
        List<String> duplicates = new ArrayList<>();

        // 遍历待比较图片的哈希值集合
        for (Map.Entry<String, String> entry : imageHashes.entrySet()) {
            String imageName = entry.getKey();
            String imageHash = entry.getValue();

            // 在原数据库图片哈希值集合中查找是否有相同的哈希值
            if (baseImageHashes.containsValue(imageHash)) {
                duplicates.add(imageName);
                duplicateCount++;
            }
        }

        return new DuplicateResult(duplicateCount, duplicates);
    }

/**
 * 根据hash比较图片是否相同
 *
 * @param  baseImagePaths   原数据库图片数据
 * @param  imagePaths 导人解压出来的图片数据
 */
//    public DuplicateResult compareImagesWithBaseline(List<String> baseImagePaths, List<String> imagePaths) {
//        if (baseImagePaths == null || imagePaths == null) {
//            throw new IllegalArgumentException("图片路径集合不能为空");
//        }
//        Map<String, List<String>> duplicatesMap = new HashMap<>(); // 使用Map存储重复图片路径
//        int duplicateCount = 0; // 引入计数器变量
//
//        // 对于每一张导入的图片,与原图集合中的所有图片进行比较
//        for (String baseImagePath : baseImagePaths) {
//            try {
//                BufferedImage baseImage = ImageIO.read(new java.io.File(baseImagePath));
//                ContrastImgUntil baseComparator = new ContrastImgUntil(baseImage);
//
//                for (String imagePath : imagePaths) {
//                    try {
//                        BufferedImage imgToCompare = ImageIO.read(new java.io.File(imagePath));
//                        ContrastImgUntil comparator = new ContrastImgUntil(imgToCompare);
//
//                        float similarity = baseComparator.compare(comparator);
//
//                        // 处理相似度结果
//                        if (similarity == SIMILARITY_THRESHOLD) {
//                            // 注意这里交换了basePath和imagePath的位置以更准确地反映哪两张图片重复
//                            String errorMsg = String.format("导入图片 '%s' 与原图 '%s' 相似度为100%%,存在重复!", imagePath, baseImagePath);
//                            System.err.println(errorMsg + "分隔符!!!");
//                            duplicateCount++; // 每发现一次重复就增加计数
//                            duplicatesMap.computeIfAbsent(baseImagePath, k -> new ArrayList<>()).add(imagePath);
//                        }
//                    } catch (IOException e) {
//                        e.printStackTrace(); // 处理解码图片时可能发生的异常
//                    } catch (Exception ice) {
//                        System.err.println(ice.getMessage());
//                    }
//                }
//            } catch (IOException e) {
//                e.printStackTrace(); // 处理解码图片时可能发生的异常
//            } catch (Exception ice) {
//                System.err.println(ice.getMessage());
//            }
//        }
//        // 将所有重复图片路径合并到一个列表中
//        List<String> allDuplicates = new ArrayList<>();
//        for (List<String> group : duplicatesMap.values()) {
//            allDuplicates.addAll(group);
//        }
//
//        // 返回重复图片的数量和重复图片
//        return new DuplicateResult(duplicateCount, allDuplicates);
//    }

以上内容繁多,请花点时间具体看写每个部分要点.

标签:hash,String,ZIP,java,return,File,new,压缩包,图片
From: https://blog.csdn.net/weixin_55746254/article/details/139393807

相关文章

  • 压缩包文件批量解压助手工具
    压缩包文件批量解压助手工具主要用于批量化解压压缩包文件,省去了繁琐的人工操作主要包含以下功能:自动获取文件夹内所有压缩包文件(支持:zip、tar、7z、uvz、rar格式)自动从密码本中匹配压缩包密码后自动解压压缩包支持解压完成后自动删除压缩包文件支持快速、标准、性能三种......
  • 使用 Sleuth 和 Zipkin 实现分布式链路追踪
    SpringCloud微服务之间的调用关系,通常随着业务的不断扩张而变得越来越复杂。如果调用链路上任何一个服务出现问题或者网络超时,导致通过日志快速排查和定位问题非常困难。分布式链路追踪就可以轻松解决该场景所面临的问题,其中一种比较简单的方案是采用SpringCloudSleuthSprin......
  • 总结常用9种下载(限速、多线程加速、ZIP、导Excel)
    一、前言下载文件在我们项目很常见,有下载视频、文件、图片、附件、导出Excel、导出Zip压缩文件等等,这里我对常见的下载做个简单的总结,主要有文件下载、限速下载、多文件打包下载、URL文件打包下载、Excel导出下载、Excel批量导出Zip包下载、多线程加速下载。二、搭建SpringBoo......
  • PHP 使用 ZipArchive 解压避免乱码
    $filePath:压缩包路径../123.zip$path:要解压的目录../unzip/publicfunctionnewUnzip($filePath,$path){$zip=new\ZipArchive();if($zip->open($filePath)===true){//创建要解压的目录//获取解压的文件数组......
  • [数据结构+二叉树+B-Tree和红黑树与B+Tree与hashMap原理+ concurrentHashMap的原理]析
    目录数据结构:你了解过哪些数据结构:这些数据结构的优缺点:二叉树:特点:二叉树适合做磁盘存储吗: 缺点:B-Tree:b-树的查找过程:思考:特点:B+Tree: B+树搜索过程与B树的查询过程没有区别。但实际上有三点不一样:(B+Tree优势)简述B+Tree:不经历IO的情况下,可以直接......
  • hashtable的常用方法
    哈希表的定义和查找方法就不再赘述,此随笔主要写代码中的用法加深自己印象。声明哈希表:#include<unordered_map>unordered_map<eleType_1,eleType_2>var_name;unordered_map<int,int>map;//或者之前用过的charint类型,char为key,int为char的值。后面的变量为两个unordered......
  • Java--hashmap如何根据value排序
    java中map根据value排序在Java中,Map是一种非常常用的数据结构,它通过键值对的形式存储数据,Map本身是无序的,但是在实际应用中,我们有时需要根据Map的值来进行排序,本文将介绍如何使用Java中的Map来实现根据Value排序。Map转TreeMap在Java中,可以使用TreeMap来根据HashMap的值......
  • VUE3+jszip和file-saver如何实现下载多个文件导出为一个zip格式
    借鉴大佬写的文章,他这个是图片的https://www.jb51.net/javascript/31723515u.htm业务场景:后端会给在线文件地址,然后根据列表点击批量下载当前存在问题会有文件跨域的情况,这个我试过几个方案都不行,只能遵循同源政策,放一起插件安装npminstalljszipnpminstallfile-saver我......
  • 【QT】QHash键值对记录QTcpSocket客户端句柄
    第一步:.h文件代码#ifndefSOCKETMAP_H#defineSOCKETMAP_H#include<QHash>#include<QDebug>#include<QTcpSocket>#include<QException>classSocketMap:publicQObject{Q_OBJECTpublic:SocketMap();public:staticboolupd......
  • 深入探索Java HashMap底层源码:结构、原理与优化
    引言简述HashMap在Java集合框架中的地位及其应用场景。阐明学习HashMap底层原理的重要性,特别是在面试、性能调优和解决并发问题方面的价值。1.HashMap基础概念数据结构:介绍HashMap的核心——哈希表,包括数组加链表/红黑树的结构。线程安全性:强调HashMap是非线程安全的,以及在......