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();
}
}