个人网站设计方案,企业网站改版计划书,wordpress+移动,诸暨市建设局网站Spring Boot 自动化脚本-多线程批量压缩图片
支持多线程支持多路径配置支持断点续压支持压缩后文件层级路径不变脚本一键启动#xff0c;支持本地 main 调用或远程 POST 接口调用
背景#xff1a;在进行数据迁移时#xff0c;发现附件文件夹过于庞大#xff0c;且大都为图…Spring Boot 自动化脚本-多线程批量压缩图片
支持多线程支持多路径配置支持断点续压支持压缩后文件层级路径不变脚本一键启动支持本地 main 调用或远程 POST 接口调用
背景在进行数据迁移时发现附件文件夹过于庞大且大都为图片格式一方面图片数量过多再一方面就是在文件上传时未对图片进行压缩导致磁盘占用过大。
解决方案写一个脚本对服务器图片进行压缩。 目标压缩后不影响图片内容查看且压缩后文件结构路径与原来一致。
安装 dependencygroupIdnet.coobird/groupIdartifactIdthumbnailator/artifactIdversion0.4.20/version/dependency压缩
Thumbnails.of(inputFile).scale(0.3) //scale是指定图片的大小值在0到1之间1就是原图大小.outputQuality(0.3) //图片的质量值也是在0到1越接近于1质量越好.toFile(outputFile);处理逻辑
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;import java.io.File;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** 解决图片附件目录过大问题压缩图片处理* 支持多线程* 支持多路径配置* 支持断点续压* 支持压缩后文件层级路径不变** author jason*/
Slf4j
public class ImgReduceService {private static final ExecutorService EXECUTOR_SERVICE Executors.newFixedThreadPool(20);public static void main(String[] args) {PathInfo pathInfo new PathInfo();pathInfo.setInputBasePath(/data/attachment);pathInfo.setOutputBasePath(/data/output/attachment);PathInfo pathInfo1 new PathInfo();pathInfo1.setInputBasePath(/data/attachment2);pathInfo1.setOutputBasePath(/data/output/attachment);ImgReduceService.start(CollectionUtil.newArrayList(pathInfo, pathInfo1));}SneakyThrowspublic static void start(ListPathInfo pathInfoList) {for (PathInfo pathInfo : pathInfoList) {String inputBasePath pathInfo.getInputBasePath();String outputBasePath pathInfo.getOutputBasePath();if (StrUtil.isBlank(inputBasePath)) {continue;}ListFile fileList FileUtil.loopFiles(inputBasePath);log.info(文件数量{}, fileList.size());for (File file : fileList) {String inputFile FileUtil.getAbsolutePath(file);String inputPath FileUtil.getAbsolutePath(FileUtil.getParent(file, 1));inputPath StrUtil.replace(inputPath, D:, );inputPath StrUtil.replace(inputPath, File.separator, /);String outputPath StrUtil.replace(inputPath, inputBasePath, );outputPath outputBasePath outputPath;FileUtil.mkdir(outputPath);// 目标文件String outputFile outputPath / file.getName();// 已存在的跳过if (FileUtil.exist(outputFile)) {log.info(目标文件已存在{}, outputFile);continue;}String regex .*\\.(jpg|jpeg|png|gif|bmp)$;boolean isImage ReUtil.isMatch(regex, file.getName());// 图片才处理if (!isImage) {// 非图片直接免压缩丢过去FileUtil.copy(inputFile, outputPath, false);continue;}// 压缩asyncReduce(inputFile, outputFile, outputPath);}}}/*** 压缩-多线程*/SneakyThrowsprivate static void asyncReduce(String inputFile, String outputFile, String outputPath) {EXECUTOR_SERVICE.execute(() - reduce(inputFile, outputFile, outputPath));}/*** 压缩-单线程*/private static void reduce(String inputFile, String outputFile, String outputPath) {try {long startTime System.currentTimeMillis();Thumbnails.of(inputFile).scale(0.3) //scale是指定图片的大小值在0到1之间1就是原图大小.outputQuality(0.3) //图片的质量值也是在0到1越接近于1质量越好.toFile(outputFile);log.info(源文件{}, inputFile);log.info(目标文件{}, outputFile);log.info(压缩耗时{}ms, System.currentTimeMillis() - startTime);// long inputSize FileUtil.size(FileUtil.file(inputFile));
// long outputSize FileUtil.size(FileUtil.file(outputFile));
// log.info(源文件大小{}压缩后大小{}, DataSizeUtil.format(inputSize), DataSizeUtil.format(outputSize));
// double f (double) inputSize / outputSize;
// log.info(压缩率{}, NumberUtil.formatPercent(f, 2));} catch (Exception e) {
// log.error(压缩异常, e);log.info(压缩异常{}源文件路径{}, e.getMessage(), inputFile);// 压缩失败直接复制FileUtil.copy(inputFile, outputPath, false);}}/*** 配置信息*/Datapublic static class PathInfo {/*** 源文件根路径*/private String inputBasePath;/*** 输入文件根路径*/private String outputBasePath;}}java 简单部署
startup.sh 启动脚本
#!/bin/bashnohup java -Xms2G -Xmx3G -jar job_api.jar app.log 21 shutdown.sh 停止脚本
#!/bin/bash# 应用名称
APP_NAMEjob_api# 查找 Java 应用的进程ID
PID$(ps -ef | grep $APP_NAME | grep -v grep | awk {print $2})# 判断是否存在进程ID
if [ -z $PID ]; thenecho 未找到名为 $APP_NAME 的进程
elseecho 正在终止名为 $APP_NAME 的进程进程ID为$PIDkill -9 $PID
fi支持代码调用和接口调用
curl http://127.0.0.1:9092/job/index/reduce \
--header Content-Type: application/json \
--data
[{inputBasePath: /home/env/attachment,outputBasePath: /home/env/output/attachment},{inputBasePath: /home/env/attachment2,outputBasePath: /home/env/output/attachment}
]源码
https://gitee.com/zhaomingjian/workspace_jason_demo/tree/master/spring-boot-thumbnails