知识库-向量化功能-读取PDF文件内容的方法

知识库-向量化功能-读取PDF文件内容的方法

一、核心逻辑

基于Apache PDFBox组件解析PDF文件,仅提取原生文本内容(不处理图片、扫描件,也不涉及OCR光学字符识别),解析后对文本做格式化处理,为后续向量化提供干净的数据源。

二、依赖配置(Maven)

xml 复制代码
<!-- PDF文本解析核心依赖 -->
<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>3.0.2</version> <!-- 稳定版本,兼容主流PDF格式 -->
</dependency>

说明:PDFBox 3.0.2适配Java 8+,若项目为低版本Java,可降级至2.0.x系列(如2.0.32)。

三、核心实现代码

3.1 配置类(支持扩展OCR)

java 复制代码
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * PDF解析配置类(预留OCR扩展能力,默认仅提取原生文本)
 */
public static class Config {
    // 核心配置:是否提取原生文本(默认开启)
    private boolean extractNativeText = true;
    // OCR扩展配置(当前功能未启用,仅预留)
    private String ocrLanguage = "chi_sim+eng"; // 识别语言(中文+英文)

    /**
     * 设置是否提取原生文本
     * @param enable 开启/关闭
     * @return 配置对象(链式调用)
     */
    public Config extractNativeText(boolean enable) {
        this.extractNativeText = enable;
        return this;
    }

    /**
     * 设置OCR识别语言(预留配置)
     * @param lang 语言编码(如chi_sim=简体中文,eng=英文)
     * @return 配置对象(链式调用)
     */
    public Config ocrLanguage(String lang) {
        this.ocrLanguage = lang;
        return this;
    }

    // 配置项getter(按需添加)
    public boolean isExtractNativeText() {
        return extractNativeText;
    }

    public String getOcrLanguage() {
        return ocrLanguage;
    }
}

3.2 结果封装类

java 复制代码
/**
 * PDF解析结果封装类
 */
public static class OcrResult {
    // 原生文本内容(核心字段)
    public String nativeText = "";
    // OCR文本(预留字段,当前未启用)
    public String ocrText = "";
    // 图片路径(预留字段,当前未启用)
    public List<String> imagePaths = new ArrayList<>();

    /**
     * 获取合并后的文本(当前仅返回原生文本)
     * @return 格式化后的原生文本
     */
    public String getCombinedText() {
        return nativeText;
    }
}

3.3 核心解析方法

java 复制代码
/**
 * 核心PDF处理方法(仅提取原生文本)
 * @param pdfFile 待解析的PDF文件
 * @param config 解析配置
 * @return 解析结果对象
 * @throws Exception 文件读取/解析异常
 */
public static OcrResult process(File pdfFile, Config config) throws Exception {
    OcrResult result = new OcrResult();
    // 资源自动关闭,避免文件句柄泄漏
    try (PDDocument doc = org.apache.pdfbox.Loader.loadPDF(pdfFile)) {
        // 仅处理原生文本提取(核心逻辑)
        if (config.isExtractNativeText()) {
            String nativeText = extractNativeText(doc);
            result.nativeText = nativeText;
            // 预留:智能触发OCR的逻辑(当前功能未启用)
            // boolean needOcr = nativeText.trim().length() < 100; // 示例:文本过短时触发OCR
        }
        // OCR处理逻辑(当前功能未启用,预留扩展)
    }
    return result;
}

/**
 * 提取PDF原生文本
 * @param doc PDF文档对象
 * @return 原始文本内容
 * @throws IOException 解析异常
 */
private static String extractNativeText(PDDocument doc) throws IOException {
    PDFTextStripper stripper = new PDFTextStripper();
    // 可选:设置提取页码范围(如stripper.setStartPage(1); stripper.setEndPage(5);)
    return stripper.getText(doc);
}

3.4 文本格式化方法

java 复制代码
/**
 * 格式化PDF解析后的文本,清理冗余字符
 * @param content 原始解析文本
 * @return 格式化后的干净文本
 */
public static String trimContent(String content) {
    if (content == null || content.isEmpty()) {
        return "";
    }
    return content
            .replaceAll("-\\n", "")        // 合并PDF断行(如"文本-\\n换行"→"文本换行")
            .replaceAll("\\s{2,}", " ")    // 压缩连续空格(多个空格→单个空格)
            .replaceAll("(?m)^\\d+$", "")  // 删除纯数字页码行(仅匹配整行数字)
            .replaceAll("\\r\\n|\\r|\\n", " ") // 统一换行符为空格
            .trim();                       // 去除首尾空白
}

3.5 统一调用入口

java 复制代码
/**
 * 统一读取PDF文件文本内容
 * @param filePath PDF文件绝对路径
 * @return 格式化后的纯文本
 * @throws RuntimeException 解析失败异常
 */
public static String getContent(String filePath) {
    // 初始化配置:仅提取原生文本,预留OCR语言配置
    Config config = new Config()
            .extractNativeText(true)
            .ocrLanguage("chi_sim+eng"); // 中文+英文(预留配置)

    try {
        File file = new File(filePath);
        // 前置校验:文件存在性、合法性
        if (!file.exists()) {
            throw new FileNotFoundException("PDF文件不存在:" + filePath);
        }
        if (!file.isFile() || !filePath.endsWith(".pdf")) {
            throw new IllegalArgumentException("非合法PDF文件:" + filePath);
        }

        OcrResult result = process(file, config);
        String combinedText = result.getCombinedText();
        // 格式化文本,返回干净数据
        return trimContent(combinedText);
    } catch (Exception e) {
        throw new RuntimeException("PDF文本提取失败: " + e.getMessage(), e);
    }
}

四、核心设计说明

4.1 关键优化点

设计点 解决的问题
仅提取原生文本 避免OCR带来的性能损耗,聚焦文本向量化核心需求
资源自动关闭(try-with-resources) 解决PDF文档对象/文件流未关闭导致的句柄泄漏
文本格式化处理 清理PDF解析后的断行、冗余空格、页码,提升后续向量化准确性
前置文件校验 提前拦截"文件不存在""非PDF文件"等基础异常
链式配置类 便于扩展OCR等功能,保持代码可读性

4.2 方法调用示例

java 复制代码
// 调用示例
public static void main(String[] args) {
    try {
        String pdfText = getContent("D:/test.pdf");
        System.out.println("PDF解析后的文本:" + pdfText);
    } catch (RuntimeException e) {
        System.err.println("解析失败:" + e.getMessage());
        e.printStackTrace();
    }
}

五、注意事项

  1. 格式支持范围:仅支持原生文本PDF(可复制文字的PDF),扫描件/图片型PDF解析后无内容(需扩展OCR);
  2. 特殊内容处理 :PDFBox会忽略PDF中的图片、表单、批注,仅提取文本;若需解析表格,需额外适配PDFTextStripperByArea
  3. 性能优化 :解析大PDF(>100MB)时,建议分页码解析(设置startPage/endPage),避免内存溢出;
  4. 编码问题:PDFBox默认采用UTF-8编码,解析乱码时可检查PDF文件本身的编码格式;
  5. 依赖冲突 :若项目中存在其他PDFBox版本,需统一为3.0.2,避免NoSuchMethodError
  6. 权限问题 :解析网络路径/只读文件时,需确保文件读取权限,避免AccessDeniedException

六、扩展建议

  1. 分页码解析 :在extractNativeText方法中增加页码范围参数,支持指定页码提取;
  2. 异步解析:结合线程池实现大批量PDF异步解析,提升处理效率;
  3. OCR扩展:集成Tesseract OCR,实现"原生文本+OCR"混合解析(适配扫描件PDF);
  4. 进度监控:解析大文件时增加进度回调,便于前端展示解析进度;
  5. 容错处理:对损坏的PDF文件增加重试机制,或返回空字符串避免程序崩溃;
  6. 日志记录:增加解析日志(文件路径、解析耗时、文本长度),便于问题排查;
  7. 大小限制 :在getContent方法中增加文件大小校验(如限制最大解析200MB),避免内存耗尽。
相关推荐
yangminlei16 小时前
Spring Boot3集成LiteFlow!轻松实现业务流程编排
java·spring boot·后端
计算机毕设VX:Fegn089516 小时前
计算机毕业设计|基于springboot + vue医院设备管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
J_liaty16 小时前
Spring Boot整合Nacos:从入门到精通
java·spring boot·后端·nacos
面汤放盐16 小时前
后端系统设计文档模板
后端
2***d88517 小时前
SpringBoot 集成 Activiti 7 工作流引擎
java·spring boot·后端
五阿哥永琪17 小时前
Spring中的定时任务怎么用?
java·后端·spring
追逐时光者17 小时前
C#/.NET/.NET Core技术前沿周刊 | 第 65 期(2026年1.1-1.11)
后端·.net
计算机毕设VX:Fegn089517 小时前
计算机毕业设计|基于springboot + vue小型房屋租赁系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
gelald17 小时前
AQS 工具之 CountDownLatch 与 CyclicBarry 学习笔记
java·后端·源码阅读
且去填词17 小时前
Go 语言的“反叛”——为什么少即是多?
开发语言·后端·面试·go