lyh
2026-03-23 ae9c823ff91b6b0c73139792ccf5c622575f999b
src/main/java/com/lxzn/framework/utils/file/FileUtil.java
@@ -5,7 +5,6 @@
import com.lxzn.framework.exception.ExceptionCast;
import com.lxzn.framework.utils.SHA256Util;
import com.lxzn.framework.utils.date.DateUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
@@ -17,7 +16,9 @@
import java.net.URLEncoder;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
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;
@@ -28,6 +29,11 @@
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) {
@@ -62,6 +68,179 @@
        dto.setFileSize(fileSize);
        dto.setFileSuffix(suffix);
        return dto;
    }
    /**
     * 方法一:使用 FileWriter 写文件
     * @param filepath 文件目录
     * @param content  待写入内容
     * @throws IOException
     */
    public static void fileWriterSql(String filepath, String content) throws IOException {
        OutputStreamWriter outputStreamWriter = null;
        try {
            File file = new File(filepath);
            if (!file.exists()){
                file.createNewFile();
            }
            FileOutputStream outputStream = new FileOutputStream(file);
            if (outputStream != null){
                outputStreamWriter = new OutputStreamWriter(outputStream, "utf-8");
                outputStreamWriter.write(content);
                outputStreamWriter.flush();
            }
            try {
                if (outputStreamWriter != null){
                    outputStreamWriter.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        catch (IOException e) {
            e.getMessage();
        }
        finally {
            try {
                if (outputStreamWriter != null){
                    outputStreamWriter.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 删除文件
     *
     * @param filePath
     * @return
     */
    public static boolean deleteNcFile(String filePath) {
        String lastFileReName =  fileUploadFolder + "/" + filePath ;
        boolean flag = false;
        File file = new File(lastFileReName);
        if (!file.exists()) {
            return flag;
        }
        boolean b = file.delete();
        if (!b) {
            System.out.println("文件删除失败: " + filePath);
        }
        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. 如果指定了新的扩展名,则附加到目标文件名
        if (StringUtils.isNotBlank(ncFix)) {
            targetFilePath = targetFilePath + "." + 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;
        }
        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. 执行复制操作(使用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) {
@@ -179,6 +358,54 @@
            log.error(e.getMessage());
        }
        return -1;
    }
    /**
     * 删除文件
     *
     * @param filePath
     * @return
     */
    public static boolean deleteFile(String filePath) {
        boolean flag = false;
        File file = new File(filePath);
        if (!file.exists()) {
            return flag;
        }
        boolean b = file.delete();
        if (!b) {
            try {
                System.gc();
                Path path = Paths.get(filePath);
                Files.deleteIfExists(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }
    /**
     *
     * @param file
     * @return
     */
    public static long selectFileSize(File file) {
        try (FileInputStream fis = new FileInputStream(file)) {
            long size = 0;
            int read;
            byte[] buffer = new byte[1024];
            while ((read = fis.read(buffer)) != -1) {
                size += read;
            }
            return size;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }
    /**
@@ -438,7 +665,6 @@
        }
    }
    public static String getFileAbsPath(String path, String fileName){
        path = fileUploadFolder + path;
        File file = new File(path, fileName);
@@ -448,5 +674,12 @@
        return null;
    }
    public static String getFileAbsPathTxt(String path){
        File file = new File(path);
        if(file.exists()){
            return file.getAbsolutePath();
        }
        return null;
    }
}