lyh
10 天以前 30c9299fa9ffc8d3cd51d4a18b4c0b33c3ef8141
src/main/java/com/lxzn/framework/utils/file/FileUtil.java
@@ -19,7 +19,6 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -29,11 +28,7 @@
public class FileUtil {
    private static String fileUploadFolder;
    private static String fileNcGateway;
    @Value("${fileNcGateway}")
    public void setFileNcGateway(String fileNcGateway) {
        FileUtil.fileNcGateway = fileNcGateway;
    }
    @Value("${fileHomePath}")
    public void setFileUploadFolder(String fileUploadFolder) {
@@ -131,116 +126,28 @@
        return true;
    }
    /**
     * 复制文件(带重试、大小校验和MD5校验,确保复制完整性与可靠性)
     * 从 fileUploadFolder 下的源路径复制到 fileNcGateway 下的目标路径,可指定新的文件扩展名
     * @param lastFile 源文件的相对路径(相对于 fileUploadFolder)
     * @param newFile 目标文件的相对路径(相对于 fileNcGateway)
     * @param ncFix (可选)目标文件的新扩展名(不带点,如 "txt"),传入 null 或空字符串则不修改原扩展名
     * @return 复制成功返回 true,否则返回 false
     */
    public static boolean copyFileUpName(String lastFile, String newFile, String ncFix) {
        // 1. 构建源文件和目标文件的绝对路径
        String sourceFilePath = fileUploadFolder + "/" + lastFile;
        String targetFilePath = newFile;
        // 2. 如果指定了新的扩展名,则附加到目标文件名
        String lastFileReName =  fileUploadFolder + "/" + lastFile ;
        if (StringUtils.isNotBlank(ncFix)) {
            targetFilePath = targetFilePath + "." + ncFix;
            newFile =  newFile + "." + ncFix;
        }
        // 3. 创建目标文件夹
        File targetFile = new File(targetFilePath);
        File targetParentDir = targetFile.getParentFile();
        if (!targetParentDir.exists() && !targetParentDir.mkdirs()) {
            log.error("无法创建目标文件夹: {}", targetParentDir.getAbsolutePath());
            return false;
        }
        // 4. 获取源文件预期大小
        long expectedSize = -1;
        File sourceFile = new File(sourceFilePath);
        if (!sourceFile.exists()) {
            log.error("源文件不存在: {}", sourceFilePath);
            return false;
        File toFile = new File(newFile);
        if (!toFile.getParentFile().exists()) {
            toFile.mkdirs();
        }
        try {
            expectedSize = sourceFile.length();
            log.info("文件复制: 源={}, 目标={}, 大小={}字节", sourceFilePath, targetFilePath, expectedSize);
        } catch (SecurityException e) {
            log.error("无法访问源文件: {}", sourceFilePath, e);
            long begintime = System.currentTimeMillis(); // 获取拷贝文件前的系统时间
            Files.copy(Paths.get(lastFileReName),
                    Paths.get(newFile),
                    StandardCopyOption.REPLACE_EXISTING);
            long endtime = System.currentTimeMillis(); // 获取文件拷贝结束时的系统时间
            System.out.println("拷贝文件所消耗的时间是:" + (endtime - begintime) + "毫秒");
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        // 5. 复制操作(最多重试3次)
        int maxRetries = 3;
        int attempt = 0;
        boolean copySuccess = false;
        while (attempt < maxRetries && !copySuccess) {
            attempt++;
            try {
                log.info("---- 开始第{}次复制尝试 ----", attempt);
                // 6. 执行复制操作(使用NIO FileChannel以提高效率)
                long startTime = System.currentTimeMillis();
                try (FileChannel in = new FileInputStream(sourceFilePath).getChannel();
                     FileChannel out = new FileOutputStream(targetFilePath).getChannel()) {
                    out.transferFrom(in, 0, in.size());
                }
                long endTime = System.currentTimeMillis();
                log.info("文件传输完成,耗时: {}毫秒", (endTime - startTime));
                // 7. 文件大小验证
                File copiedFile = new File(targetFilePath);
                long actualSize = copiedFile.length();
                if (expectedSize != actualSize) {
                    log.warn("大小不一致! 预期: {}B, 实际: {}B (差值: {}B)",
                            expectedSize, actualSize, Math.abs(actualSize - expectedSize));
                } else {
                    log.info("文件大小验证成功: {}B", actualSize);
                    copySuccess = true;
                }
                // 8. MD5校验
                if (copySuccess) {
                    String sourceMd5 = calculateMD5(sourceFilePath);
                    String targetMd5 = calculateMD5(targetFilePath);
                    if (!sourceMd5.equals(targetMd5)) {
                        log.warn("MD5不一致! 源: {}, 目标: {}", sourceMd5, targetMd5);
                        copySuccess = false;
                    } else {
                        log.info("MD5验证成功");
                    }
                }
            } catch (IOException | SecurityException e) {
                log.error("第{}次复制失败", attempt, e);
            }
            // 9. 重试间隔处理
            if (!copySuccess && attempt < maxRetries) {
                try {
                    int delay = 200 * attempt; // 递增延迟:200ms, 400ms
                    log.info("等待 {}ms 后重试", delay);
                    Thread.sleep(delay);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    log.warn("重试等待被中断", ie);
                    break; // 如果线程被中断,则退出重试循环
                }
            }
        }
        if (copySuccess) {
            log.info("文件复制完成: {}", targetFilePath);
        } else {
            log.error("文件复制失败,已尝试{}次。源文件: {}, 目标文件: {}", maxRetries, sourceFilePath, targetFilePath);
        }
        return copySuccess;
    }
    public static FileUploadResult uploadFile(String fileName, InputStream fis) {
@@ -536,133 +443,41 @@
    }
    /**
     * 复制文件(带重试和校验-防止中科方德复制文件出错问题)
     * 复制文件
     * @param oldPath
     * @param newPath
     * @param fileName
     */
    public static boolean copyFile(String oldPath, String newPath, String fileName){
        // 1. 路径规范化
        String absolutePathSend = fileUploadFolder + oldPath;
        String absolutePathTarget = fileUploadFolder + newPath;
        // 2. 创建目标文件夹
        File targetFolder = new File(absolutePathTarget);
        if (!targetFolder.exists() && !targetFolder.mkdirs()) {
            log.error("无法创建目标文件夹: {}", absolutePathTarget);
            return false;
        oldPath = fileUploadFolder + oldPath;
        newPath = fileUploadFolder + newPath;
        File oldFile = new File(oldPath, fileName);
        File newFile = new File(newPath, fileName);
        if(oldFile.exists()){
            if(!newFile.getParentFile().exists()){
                newFile.getParentFile().mkdirs();
        }
        // 3. 源文件和目标文件路径
        String sourceFilePath = absolutePathSend + File.separator + fileName;
        String targetFilePath = absolutePathTarget + File.separator + fileName;
        // 4. 获取源文件预期大小
        long expectedSize = -1;
        File sourceFile = new File(sourceFilePath);
        if (!sourceFile.exists()) {
            log.error("源文件不存在: {}", sourceFilePath);
            return false;
        }
            FileChannel inputChannel = null;
            FileChannel outputChannel = null;
        try {
            expectedSize = sourceFile.length();
            log.info("文件复制: 源={}, 目标={}, 大小={}字节", sourceFilePath, targetFilePath, expectedSize);
        } catch (SecurityException e) {
            log.error("无法访问源文件: {}", sourceFilePath, e);
            return false;
        }
        // 5. 复制操作(最多重试3次)
        int maxRetries = 3;
        int attempt = 0;
        boolean copySuccess = false;
        while (attempt < maxRetries && !copySuccess) {
            attempt++;
            try {
                log.info("---- 开始第{}次复制尝试 ----", attempt);
                // 6. 执行复制操作
                try (FileChannel in = new FileInputStream(sourceFilePath).getChannel();
                     FileChannel out = new FileOutputStream(targetFilePath).getChannel()) {
                    out.transferFrom(in, 0, in.size());
                }
                // 7. 文件大小验证
                File copiedFile = new File(targetFilePath);
                long actualSize = copiedFile.length();
                if (expectedSize != actualSize) {
                    log.warn("大小不一致! 预期: {}B, 实际: {}B (差值: {}B)",
                            expectedSize, actualSize, Math.abs(actualSize - expectedSize));
                } else {
                    log.info("文件大小验证成功: {}B", actualSize);
                    copySuccess = true;
                }
                // 8. MD5校验
                if (copySuccess) {
                    String sourceMd5 = calculateMD5(sourceFilePath);
                    String targetMd5 = calculateMD5(targetFilePath);
                    if (!sourceMd5.equals(targetMd5)) {
                        log.warn("MD5不一致! 源: {}, 目标: {}", sourceMd5, targetMd5);
                        copySuccess = false;
                    } else {
                        log.info("MD5验证成功");
                    }
                }
            } catch (IOException | SecurityException e) {
                log.error("第{}次复制失败", attempt, e);
            }
            // 9. 重试间隔处理
            if (!copySuccess && attempt < maxRetries) {
                try {
                    int delay = 200 * attempt; // 递增延迟:200ms, 400ms
                    log.info("等待 {}ms 后重试", delay);
                    Thread.sleep(delay);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                }
            }
        }
        if (copySuccess) {
            log.info("文件复制完成: {}", targetFilePath);
        } else {
            log.error("文件复制失败,已尝试{}次", maxRetries);
        }
        return copySuccess;
    }
    /**
     * 计算文件的MD5值
     * @param filePath
     * @return
     */
    public static String calculateMD5(String filePath) {
        try (InputStream is = Files.newInputStream(Paths.get(filePath))) {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] buffer = new byte[8192];
            int read;
            while ((read = is.read(buffer)) != -1) {
                md.update(buffer, 0, read);
            }
            byte[] digest = md.digest();
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
                inputChannel = new FileInputStream(oldFile).getChannel();
                outputChannel = new FileOutputStream(newFile).getChannel();
                outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
                return true;
        } catch (Exception e) {
            throw new RuntimeException("计算MD5失败: " + filePath, e);
                log.error("复制文件错误{}", e);
                return false;
            }finally {
                try {
                    inputChannel.close();
                    outputChannel.close();
                }catch (Exception e){
                    log.error("复制文件错误{}", e);
        }
            }
        }
        return false;
    }
    public static String getFileAbsPath(String path, String fileName){