PowerPoint 批量转换为 PDF

为了满足批量文档转换需求,新增了 PowerPoint 批量转换功能。

功能特性
  1. 批量转换 :自动扫描目录下所有 .pptx.ppt 文件
  2. 智能跳过:已存在的 PDF 文件自动跳过
  3. 进度跟踪:实时显示转换进度和结果
  4. 错误处理:完善的异常处理和错误报告
  5. 超时控制:单个文件转换超时时间为 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

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



相关推荐
2501_930707782 小时前
使用 C# 将 PDF 转换为 PCL
pdf
java1234_小锋2 小时前
Java高频面试题:RabbitMQ如何实现消息的持久化?
java·开发语言
爱打代码的小林2 小时前
用 LangChain 解析大模型输出
java·python·langchain·大模型
_日拱一卒2 小时前
LeetCode(力扣):只出现一次的数字
java·数据结构·算法
小箌2 小时前
JavaWeb_02
java·数据库·maven·mybatis
gxy1990262 小时前
【springboot】Spring 官方抛弃了 Java 8!新idea如何创建java8项目
java·spring boot·spring
阿杰真不会敲代码2 小时前
Elasticsearch 入门到实战:安装 + CRUD + 查询
java·大数据·elasticsearch·搜索引擎
老邋遢2 小时前
干货篇|02. 纯AI Coding商业应用
java·人工智能
阴暗扭曲实习生2 小时前
135编辑器开放平台架构解析:企业级富文本接入方案的技术实现
java·开发语言·中间件