为了满足批量文档转换需求,新增了 PowerPoint 批量转换功能。
功能特性
- 批量转换 :自动扫描目录下所有
.pptx和.ppt文件 - 智能跳过:已存在的 PDF 文件自动跳过
- 进度跟踪:实时显示转换进度和结果
- 错误处理:完善的异常处理和错误报告
- 超时控制:单个文件转换超时时间为 120 秒
核心类
类名 :PptxToPdfBatchConverter
位置 :src/main/java/com/util/PptxToPdfBatchConverter.java
主要方法
1. 批量转换
java
public static List<ConversionResult> convertAllPptxToPdf(String sourceDir)
参数:
sourceDir:源目录路径(如:C:\baidunetdiskdownload\00\01)
返回值:
List<ConversionResult>:转换结果列表
功能:
- 扫描目录下所有 PowerPoint 文件
- 逐个转换为 PDF
- 返回详细的转换结果
2. 单文件转换
java
public static ConversionResult convertSinglePptxToPdf(String pptxFilePath)
参数:
pptxFilePath:PowerPoint 文件完整路径
返回值:
ConversionResult:转换结果对象
功能:
- 转换单个 PowerPoint 文件
- 检查 PDF 是否已存在
- 验证 LibreOffice 安装状态
转换结果类
java
public static class ConversionResult {
private String sourceFile; // 源文件路径
private String targetFile; // 目标 PDF 路径
private boolean success; // 是否成功
private boolean skipped; // 是否跳过(已存在)
private String errorMessage; // 错误信息
private long durationMs; // 转换耗时(毫秒)
}
依赖要求
必须安装 LibreOffice:
- Windows:下载并安装 LibreOffice
- mac 安装 LibreOffice
- centos 上安装 LibreOffice
PowerPoint 批量转换
方法 1:使用测试类
java
@Test
public void testConvertAllPptxToPdf() {
String sourceDir = "C:\\baidunetdiskdownload\\00\\01";
List<PptxToPdfBatchConverter.ConversionResult> results =
PptxToPdfBatchConverter.convertAllPptxToPdf(sourceDir);
// 查看结果
for (ConversionResult result : results) {
System.out.println(result);
}
}
方法 2:直接运行主方法
java
public static void main(String[] args) {
String sourceDir = "C:\\baidunetdiskdownload\\00\\01";
PptxToPdfBatchConverter.convertAllPptxToPdf(sourceDir);
}
方法 3:在代码中调用
java
// 批量转换
List<ConversionResult> results =
PptxToPdfBatchConverter.convertAllPptxToPdf("目录路径");
// 单文件转换
ConversionResult result =
PptxToPdfBatchConverter.convertSinglePptxToPdf("文件路径.pptx");
输出示例
java
2026-03-10 12:00:00 INFO 找到 5 个 PowerPoint 文件,开始转换...
2026-03-10 12:00:05 INFO 开始转换: 第一章.pptx
2026-03-10 12:00:10 INFO 转换成功: 第一章.pptx -> 第一章.pdf (耗时: 5000ms)
2026-03-10 12:00:10 INFO 进度: 1/5 - 成功
2026-03-10 12:00:10 INFO PDF 文件已存在,跳过: 第二章.pdf
2026-03-10 12:00:10 INFO 进度: 2/5 - 成功
...
2026-03-10 12:00:30 INFO 转换完成!成功: 5, 失败: 0
========== 转换结果详情 ==========
[成功] C:\...\第一章.pptx -> C:\...\第一章.pdf (耗时: 5000ms)
[跳过] C:\...\第二章.pptx (已存在)
[成功] C:\...\第三章.pptx -> C:\...\第三章.pdf (耗时: 4500ms)
...
技术细节
java
1. 扫描目录,查找所有 .pptx/.ppt 文件
↓
2. 对每个文件:
├─ 检查 PDF 是否已存在
│ ├─ 是 → 跳过,标记为 skipped
│ └─ 否 → 继续
├─ 检查 LibreOffice 是否安装
│ ├─ 否 → 失败,返回错误
│ └─ 是 → 继续
├─ 执行转换命令
│ soffice --headless --convert-to pdf --outdir <dir> <file>
├─ 等待转换完成(最多 120 秒)
│ ├─ 超时 → 失败,返回错误
│ └─ 完成 → 继续
├─ 验证 PDF 文件是否生成
│ ├─ 否 → 失败,返回错误
│ └─ 是 → 成功
└─ 记录结果(成功/失败/跳过)
↓
3. 返回所有转换结果
完整代码
PptxToPdfBatchConverter
java
package com.util;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* PowerPoint 批量转换为 PDF 工具类
*
* @author System
* @date 2026-03-10
*/
@Slf4j
public class PptxToPdfBatchConverter {
/**
* 批量转换指定目录下的所有 .pptx 文件为 PDF
*
* @param sourceDir 源目录路径
* @return 转换结果列表
*/
public static List<ConversionResult> convertAllPptxToPdf(String sourceDir) {
List<ConversionResult> results = new ArrayList<>();
File directory = new File(sourceDir);
if (!directory.exists() || !directory.isDirectory()) {
log.error("目录不存在或不是有效目录: {}", sourceDir);
return results;
}
// 查找所有 .pptx 文件
File[] pptxFiles = directory.listFiles((dir, name) ->
name.toLowerCase().endsWith(".pptx") || name.toLowerCase().endsWith(".ppt"));
if (pptxFiles == null || pptxFiles.length == 0) {
log.warn("目录中没有找到 PowerPoint 文件: {}", sourceDir);
return results;
}
log.info("找到 {} 个 PowerPoint 文件,开始转换...", pptxFiles.length);
// 逐个转换
for (File pptxFile : pptxFiles) {
ConversionResult result = convertSinglePptxToPdf(pptxFile.getAbsolutePath());
results.add(result);
// 打印进度
log.info("进度: {}/{} - {}",
results.size(), pptxFiles.length,
result.isSuccess() ? "成功" : "失败");
}
// 打印汇总
long successCount = results.stream().filter(ConversionResult::isSuccess).count();
log.info("转换完成!成功: {}, 失败: {}", successCount, results.size() - successCount);
return results;
}
/**
* 转换单个 PowerPoint 文件为 PDF
*
* @param pptxFilePath PowerPoint 文件路径
* @return 转换结果
*/
public static ConversionResult convertSinglePptxToPdf(String pptxFilePath) {
ConversionResult result = new ConversionResult();
result.setSourceFile(pptxFilePath);
try {
File pptxFile = new File(pptxFilePath);
if (!pptxFile.exists()) {
result.setSuccess(false);
result.setErrorMessage("文件不存在");
return result;
}
// 生成 PDF 文件路径
String pdfFilePath = pptxFilePath.replaceAll("\\.(pptx|ppt)$", ".pdf");
result.setTargetFile(pdfFilePath);
// 检查 PDF 是否已存在
File pdfFile = new File(pdfFilePath);
if (pdfFile.exists()) {
log.info("PDF 文件已存在,跳过: {}", pdfFilePath);
result.setSuccess(true);
result.setSkipped(true);
return result;
}
// 检查 LibreOffice 是否安装
if (!isLibreOfficeInstalled()) {
result.setSuccess(false);
result.setErrorMessage("LibreOffice 未安装");
return result;
}
// 执行转换
String outputDir = pptxFile.getParent();
String[] command = {
"soffice",
"--headless",
"--convert-to", "pdf",
"--outdir", outputDir,
pptxFilePath
};
log.info("开始转换: {}", pptxFile.getName());
long startTime = System.currentTimeMillis();
Process process = Runtime.getRuntime().exec(command);
boolean finished = process.waitFor(120, TimeUnit.SECONDS); // 2分钟超时
if (!finished) {
process.destroyForcibly();
result.setSuccess(false);
result.setErrorMessage("转换超时(超过120秒)");
return result;
}
int exitValue = process.exitValue();
if (exitValue != 0) {
result.setSuccess(false);
result.setErrorMessage("转换失败,退出码: " + exitValue);
return result;
}
// 验证 PDF 文件是否生成
if (!pdfFile.exists()) {
result.setSuccess(false);
result.setErrorMessage("PDF 文件未生成");
return result;
}
long duration = System.currentTimeMillis() - startTime;
result.setSuccess(true);
result.setDurationMs(duration);
log.info("转换成功: {} -> {} (耗时: {}ms)",
pptxFile.getName(), pdfFile.getName(), duration);
} catch (IOException e) {
result.setSuccess(false);
result.setErrorMessage("IO 错误: " + e.getMessage());
log.error("转换失败: {}", pptxFilePath, e);
} catch (InterruptedException e) {
result.setSuccess(false);
result.setErrorMessage("转换被中断: " + e.getMessage());
log.error("转换被中断: {}", pptxFilePath, e);
Thread.currentThread().interrupt();
} catch (Exception e) {
result.setSuccess(false);
result.setErrorMessage("未知错误: " + e.getMessage());
log.error("转换失败: {}", pptxFilePath, e);
}
return result;
}
/**
* 检查 LibreOffice 是否已安装
*/
private static boolean isLibreOfficeInstalled() {
try {
Process process = Runtime.getRuntime().exec(new String[]{"soffice", "--version"});
return process.waitFor(5, TimeUnit.SECONDS) && process.exitValue() == 0;
} catch (Exception e) {
log.error("检查 LibreOffice 安装状态失败", e);
return false;
}
}
/**
* 转换结果类
*/
public static class ConversionResult {
private String sourceFile;
private String targetFile;
private boolean success;
private boolean skipped;
private String errorMessage;
private long durationMs;
public String getSourceFile() {
return sourceFile;
}
public void setSourceFile(String sourceFile) {
this.sourceFile = sourceFile;
}
public String getTargetFile() {
return targetFile;
}
public void setTargetFile(String targetFile) {
this.targetFile = targetFile;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public boolean isSkipped() {
return skipped;
}
public void setSkipped(boolean skipped) {
this.skipped = skipped;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public long getDurationMs() {
return durationMs;
}
public void setDurationMs(long durationMs) {
this.durationMs = durationMs;
}
@Override
public String toString() {
if (skipped) {
return String.format("[跳过] %s (已存在)", sourceFile);
}
if (success) {
return String.format("[成功] %s -> %s (耗时: %dms)",
sourceFile, targetFile, durationMs);
} else {
return String.format("[失败] %s - 原因: %s", sourceFile, errorMessage);
}
}
}
/**
* 主方法 - 用于测试
*/
public static void main(String[] args) {
String sourceDir = "C:\\baidunetdiskdownload\\00\\01";
log.info("开始批量转换 PowerPoint 文件...");
log.info("源目录: {}", sourceDir);
List<ConversionResult> results = convertAllPptxToPdf(sourceDir);
// 打印详细结果
log.info("\n========== 转换结果详情 ==========");
for (ConversionResult result : results) {
log.info(result.toString());
}
}
}
PptxToPdfBatchConverterTest
java
package com.hzys.util;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import java.util.List;
/**
* PowerPoint 批量转换测试类
*
* @author System
* @date 2026-03-10
*/
@Slf4j
public class PptxToPdfBatchConverterTest {
@Test
public void testConvertAllPptxToPdf() {
// 设置源目录
String sourceDir = "C:\\baidunetdiskdownload\\00\\01";
log.info("========== 开始批量转换 PowerPoint 文件 ==========");
log.info("源目录: {}", sourceDir);
// 执行批量转换
List<PptxToPdfBatchConverter.ConversionResult> results =
PptxToPdfBatchConverter.convertAllPptxToPdf(sourceDir);
// 打印详细结果
log.info("\n========== 转换结果详情 ==========");
for (PptxToPdfBatchConverter.ConversionResult result : results) {
log.info(result.toString());
}
// 统计结果
long successCount = results.stream()
.filter(PptxToPdfBatchConverter.ConversionResult::isSuccess)
.count();
long skippedCount = results.stream()
.filter(PptxToPdfBatchConverter.ConversionResult::isSkipped)
.count();
long failedCount = results.size() - successCount;
log.info("\n========== 转换统计 ==========");
log.info("总文件数: {}", results.size());
log.info("转换成功: {}", successCount - skippedCount);
log.info("已存在跳过: {}", skippedCount);
log.info("转换失败: {}", failedCount);
}
@Test
public void testConvertSinglePptx() {
// 测试转换单个文件
String pptxFile = "C:\\baidunetdiskdownload\\00\\01\\示例文件.pptx";
log.info("测试转换单个文件: {}", pptxFile);
PptxToPdfBatchConverter.ConversionResult result =
PptxToPdfBatchConverter.convertSinglePptxToPdf(pptxFile);
log.info("转换结果: {}", result);
}
}
