java实现linux文件的解压缩(确保md5sum一致)

复制代码
package com.xlkh.device.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class LinuxTarGzUtil {

    private static final Logger logger = LoggerFactory.getLogger(LinuxTarGzUtil.class);

    /**
     * 使用Linux命令压缩目录
     * @param sourceDirPath 源目录路径(需为Linux路径格式)
     * @param outputFilePath 输出文件路径
     */
    public static String compress(String sourceDirPath, String outputFilePath) throws IOException {
        Path sourcePath = Paths.get(sourceDirPath);
        Path outputPath = buildOutputPath(sourcePath, outputFilePath);

        createParentDir(outputPath);

        // 构建新的压缩命令(保持MD5一致的关键实现)
        String[] cmd = {
                "/bin/bash",
                "-c",
                String.format(
                        "find %s -exec touch -h -t 197001010000.00 {} \\; && " +
                                "tar --sort=name --numeric-owner --no-same-permissions -cf - -C %s %s | " +
                                "gzip -n -f > %s",  // 压缩并输出
                        sourcePath.toAbsolutePath(),
                        sourcePath.getParent().toAbsolutePath(),
                        sourcePath.getFileName(),
                        outputPath.toAbsolutePath()
                )
        };

        return executeCommand(cmd, "压缩");
    }


    /**
     * 使用Linux命令解压文件
     * @param inputFilePath 压缩文件路径
     * @param outputDirPath 解压目录路径
     */
    public static String decompress(String inputFilePath, String outputDirPath) throws IOException {
        validateTarGzExtension(inputFilePath);

        // 创建输出目录
        Files.createDirectories(Paths.get(outputDirPath));

        // 构建解压命令
        String[] cmd = {
                "/bin/bash",
                "-c",
                String.format("tar -xzf %s --warning=no-timestamp --no-same-owner -C %s",
                        Paths.get(inputFilePath).toAbsolutePath(),
                        Paths.get(outputDirPath).toAbsolutePath())
        };

        return executeCommand(cmd, "解压");
    }

    private static Path buildOutputPath(Path sourcePath, String outputPathStr) {
        Path outputPath = Paths.get(outputPathStr).normalize();

        if (Files.isDirectory(outputPath)) {
            String sourceDirName = getLastNonEmptyPathPart(sourcePath);
            return outputPath.resolve(sourceDirName + ".tar.gz");
        }
        return outputPath;
    }

    private static void createParentDir(Path path) throws IOException {
        Path parent = path.getParent();
        if (parent != null && !Files.exists(parent)) {
            Files.createDirectories(parent);
            logger.info("已创建父目录:{}", parent);
        }
    }

    private static void validateTarGzExtension(String filename) {
        if (!filename.toLowerCase().endsWith(".tar.gz")) {
            throw new IllegalArgumentException("只支持.tar.gz格式文件");
        }
    }

    private static String executeCommand(String[] cmd, String operation) throws IOException {
        ProcessBuilder pb = new ProcessBuilder(cmd);
        pb.redirectErrorStream(true);

        try {
            Process process = pb.start();
            StringBuilder output = new StringBuilder();

            // 读取命令输出
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    output.append(line).append("\n");
                }
            }

            int exitCode = process.waitFor();
            if (exitCode != 0) {
                throw new IOException(operation + "失败,退出码:" + exitCode + "\n" + output);
            }

            logger.info("{}成功:{}", operation, output);
            return operation + "成功";

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException(operation + "进程被中断", e);
        }
    }

    // 保留原有路径处理方法
    private static String getLastNonEmptyPathPart(Path path) {
        Path normalized = path.normalize();
        int nameCount = normalized.getNameCount();

        // 处理根目录特殊情况(如:/app)
        if (nameCount == 0) {
            String pathStr = normalized.toString();
            int lastSeparator = pathStr.lastIndexOf(File.separatorChar);
            return lastSeparator > 0 ? pathStr.substring(lastSeparator + 1) : pathStr;
        }

        return normalized.getName(nameCount - 1).toString();
    }
}

接口调用:

验证:

复制代码
package com.xlkh.device.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class LinuxTarGzUtil {

    private static final Logger logger = LoggerFactory.getLogger(LinuxTarGzUtil.class);

    /**
     * 使用Linux命令压缩目录
* @param sourceDirPath 源目录路径(需为Linux路径格式)
* @param outputFilePath 输出文件路径
*/
public static String compress(String sourceDirPath, String outputFilePath) throws IOException {
        Path sourcePath = Paths.get(sourceDirPath);
        Path outputPath = buildOutputPath(sourcePath, outputFilePath);

        createParentDir(outputPath);

        // 构建新的压缩命令(保持MD5一致的关键实现)
String[] cmd = {
                "/bin/bash",
                "-c",
                String.format(
                        "find %s -exec touch -h -t 197001010000.00 {} \\; && " +
                                "tar --sort=name --numeric-owner --no-same-permissions -cf - -C %s %s | " +
                                "gzip -n -f > %s",  // 压缩并输出
sourcePath.toAbsolutePath(),
                        sourcePath.getParent().toAbsolutePath(),
                        sourcePath.getFileName(),
                        outputPath.toAbsolutePath()
                )
        };

        return executeCommand(cmd, "压缩");
    }


    /**
     * 使用Linux命令解压文件
* @param inputFilePath 压缩文件路径
* @param outputDirPath 解压目录路径
*/
public static String decompress(String inputFilePath, String outputDirPath) throws IOException {
        validateTarGzExtension(inputFilePath);

        // 创建输出目录
Files.createDirectories(Paths.get(outputDirPath));

        // 构建解压命令
String[] cmd = {
                "/bin/bash",
                "-c",
                String.format("tar -xzf %s --warning=no-timestamp --no-same-owner -C %s",
                        Paths.get(inputFilePath).toAbsolutePath(),
                        Paths.get(outputDirPath).toAbsolutePath())
        };

        return executeCommand(cmd, "解压");
    }

    private static Path buildOutputPath(Path sourcePath, String outputPathStr) {
        Path outputPath = Paths.get(outputPathStr).normalize();

        if (Files.isDirectory(outputPath)) {
            String sourceDirName = getLastNonEmptyPathPart(sourcePath);
            return outputPath.resolve(sourceDirName + ".tar.gz");
        }
        return outputPath;
    }

    private static void createParentDir(Path path) throws IOException {
        Path parent = path.getParent();
        if (parent != null && !Files.exists(parent)) {
            Files.createDirectories(parent);
            logger.info("已创建父目录:{}", parent);
        }
    }

    private static void validateTarGzExtension(String filename) {
        if (!filename.toLowerCase().endsWith(".tar.gz")) {
            throw new IllegalArgumentException("只支持.tar.gz格式文件");
        }
    }

    private static String executeCommand(String[] cmd, String operation) throws IOException {
        ProcessBuilder pb = new ProcessBuilder(cmd);
        pb.redirectErrorStream(true);

        try {
            Process process = pb.start();
            StringBuilder output = new StringBuilder();

            // 读取命令输出
try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    output.append(line).append("\n");
                }
            }

            int exitCode = process.waitFor();
            if (exitCode != 0) {
                throw new IOException(operation + "失败,退出码:" + exitCode + "\n" + output);
            }

            logger.info("{}成功:{}", operation, output);
            return operation + "成功";

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException(operation + "进程被中断", e);
        }
    }

    // 保留原有路径处理方法
private static String getLastNonEmptyPathPart(Path path) {
        Path normalized = path.normalize();
        int nameCount = normalized.getNameCount();

        // 处理根目录特殊情况(如:/app)
if (nameCount == 0) {
            String pathStr = normalized.toString();
            int lastSeparator = pathStr.lastIndexOf(File.separatorChar);
            return lastSeparator > 0 ? pathStr.substring(lastSeparator + 1) : pathStr;
        }

        return normalized.getName(nameCount - 1).toString();
    }
}