读取实验室原始记录单PDF内容

一.工具选取

1. Apache PDFBox

简介:

Apache PDFBox 是一个开源的纯 Java PDF 库,支持创建、渲染、打印、分割、合并和提取 PDF 内容。

优点:

  • 开源免费(Apache 2.0 许可)
  • 功能全面:支持文本提取、图像提取、PDF创建、加密/解密、表单处理等
  • 纯 Java 实现,无需依赖本地库
  • 社区活跃,文档较完善
  • 支持 PDF/A 标准

缺点:

  • 性能一般,尤其处理大文件时较慢
  • 对复杂排版(如多栏、表格)的文本提取效果一般,可能乱序
  • 内存占用较高

示例代码(文本提取):

Java 复制代码
PDDocument document = PDDocument.load(new File("example.pdf"));
PDFTextStripper stripper = new PDFTextStripper();
String text = stripper.getText(document);
document.close();

2. iText

简介:

iText 是一个功能强大的商业级 PDF 库,有开源版(AGPL)和商业授权版。

优点:

  • 功能极其强大:支持高级 PDF 操作(数字签名、水印、表单、加密等)
  • 性能较好
  • 提供对 PDF 结构的精细控制

缺点:

  • 开源版本为 AGPL,若用于闭源商业项目需购买商业许可证
  • 文本提取功能相对较弱(早期版本),虽然后续版本有所改进
  • 学习曲线较陡
    示例(文本提取,需使用 iText 7 的 pdfSweep 或 pdfCalligraph 模块):
    Java
    编辑
    PdfDocument pdfDoc = new PdfDocument(new PdfReader("example.pdf"));
    String text = PdfTextExtractor.getTextFromPage(pdfDoc.getPage(1));
    pdfDoc.close();
    注意:iText 5 的文本提取能力有限,推荐使用 iText 7 + 附加模块。

3. PDF Clown

简介:

PDF Clown 是一个开源(LGPL)的 Java PDF 库,支持读写 PDF。

优点:

  • 开源免费(LGPL)
  • 支持文本、图像、字体、元数据提取
  • 架构清晰,面向对象设计良好

缺点:

  • 更新缓慢,最新稳定版停留在 2016 年左右
  • 社区小,文档较少
  • 性能和稳定性不如 PDFBox 或 iText
  • 适用场景:小型项目、学习研究

4. Tess4J + OCR(针对扫描版PDF)

说明:

如果 PDF 是扫描件(图像型),上述工具无法直接提取文本,需结合 OCR(光学字符识别)。

方案:

  • 使用 Apache PDFBox 或其他库将 PDF 转为图像
  • 调用 Tess4J(Java 封装 Tesseract OCR)识别文字

优点:

  • 可处理扫描 PDF
  • Tesseract 开源免费

缺点:

  • 依赖本地安装 Tesseract
  • 识别准确率受图像质量影响大
  • 处理速度慢

5. pdftotext(通过 Poppler)

简介:

pdftotext 是 Poppler 项目提供的一个命令行工具,用于从 PDF 中提取文本。Poppler 是一个 C++ 编写的开源 PDF 渲染库,广泛用于 Linux 系统(如 Ubuntu、CentOS)和 macOS。

虽然 pdftotext 本身不是 Java 库,但 Java 程序可以通过 Runtime.exec() 或 ProcessBuilder 调用该命令行工具,从而实现 PDF 文本提取。

优点:

  • 文本提取准确率高:尤其对复杂布局、多栏、表格等排版,通常优于 PDFBox
  • 速度快:C++ 实现,性能优异,适合批量处理
  • 开源免费(GPL 许可)
  • 保留原始布局(可通过 -layout 参数)
  • 支持加密 PDF(如果未设权限限制)

缺点:

  • 非纯 Java 方案:需在目标系统预装 Poppler(Linux/macOS 原生支持较好,Windows 需手动安装)
  • 跨平台部署复杂:需确保每台服务器都安装了 pdftotext
  • 无法直接操作 PDF 对象(如元数据、图像、表单等)
  • 错误处理和日志较难集成到 Java 应用中
  • GPL 许可:若将 pdftotext 作为程序一部分分发,可能触发 GPL 传染性(但仅调用命令行通常不构成衍生作品,法律上存在争议,建议咨询法务)

Java 调用示例:

JAVA 复制代码
public String extractTextWithPdftotext(String pdfPath) throws IOException {
    ProcessBuilder pb = new ProcessBuilder("pdftotext", "-layout", "-enc", "UTF-8", pdfPath, "-");
    Process process = pb.start();
    try (BufferedReader reader = new BufferedReader(
            new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
        return reader.lines().collect(Collectors.joining("\n"));
    }
}

参数说明:

  • -layout:尽量保留原始文本布局
  • -enc UTF-8:指定输出编码
  • -:表示输出到 stdout

对比总结表:

工具 开源许可 文本提取能力 性能 易用性 商业友好 适合场景
PDFBox Apache 2.0 ★★★★☆ ★★☆ ★★★★ 通用文本提取、开源项目
iText AGPL / 商业授权 ★★★☆☆(需额外模块) ★★★★ ★★★ ❌(闭源需购买授权) 高级PDF操作、商业应用
PDF Clown LGPL ★★★☆☆ ★★ ★★★ ✅(注意LGPL条款) 小型项目、教学研究
Tess4J + OCR Apache 2.0 ★★★★(仅适用于图像型PDF) ★☆ ★★ 扫描版PDF、图像转文本
pdftotext (Poppler) GPL ★★★★★(布局保留好,准确率高) ★★★★★ ★★☆ ⚠️(GPL传染性,需评估合规) 高精度文本提取、服务端批量处理

推荐选择

  • 普通文本PDF提取(开源项目) → Apache PDFBox
  • 需要高级PDF功能(如签名、表单)且可付费 → iText(商业版)
  • 处理扫描PDF → PDFBox + Tess4J
  • 轻量级或学习用途 → PDF Clown(谨慎使用,因维护停滞)
  • 如果你追求高精度文本提取(尤其是学术论文、财报、多栏文档) → 优先考虑 pdftotext,前提是部署环境可控(如 Linux 服务器)。
  • 避免在无法控制部署环境的 SaaS 或客户端应用中使用 pdftotext,因其依赖外部二进制文件。

本人测试过如果是实验室仪器到处的PDF文件使用PDFBox识别内容会出现错乱现象无法准确识别,并且有数据丢失现象,使用付费的OCR识别接口不会出现数据错乱但是识别错误比较明显,最终采用了pdftotext (Poppler)识别方法,准确度高,格式保留较好。

二.安装pdftotext

Linux 系统(Ubuntu / CentOS / Debian 等)

1. 安装 Poppler(含 pdftotext)

Ubuntu / Debian:

Bash 复制代码
sudo apt update
sudo apt install poppler-utils

CentOS / RHEL / Fedora:

Bash 复制代码
# CentOS 7/8 或 RHEL(需启用 EPEL)
sudo yum install epel-release
sudo yum install poppler-utils

# 或 Fedora
sudo dnf install poppler-utils
2. 验证安装
Bash 复制代码
pdftotext -v

输出类似:

Text 复制代码
pdftotext version 22.08.0
Copyright 2005-2022 The Poppler Developers - http://poppler.freedesktop.org

如果安装版本过于老旧如:poppler-utils-0.26.5-24.el7.x86_64 ,我们可以卸载之后下载源码手动安装

安装最新版本

2.1 删除旧版本

bbash 复制代码
# 查看已安装的 poppler 相关包
rpm -qa | grep poppler

# 卸载 poppler-utils 及依赖(谨慎:可能影响其他软件)
sudo yum remove poppler-utils poppler-glib poppler-qt4 poppler-qt5

#更新动态链接库缓存
sudo ldconfig

2.2 下载最新源码

前往 https://poppler.freedesktop.org/ 获取最新版(如 poppler-23.08.0.tar.xz)

bash 复制代码
cd /home
wget https://poppler.freedesktop.org/poppler-23.08.0.tar.xz
tar -xf poppler-25.10.0.tar.xz
cd poppler-25.10.0

2.3 配置编译选项(使用 CMake)

2.3.1 安装CMake

bash 复制代码
# 1. 卸载旧版 cmake(可选,避免混淆)
sudo yum remove cmake

# 2. 下载 CMake 3.28.3(或最新 LTS 版)Linux x86_64 二进制包
cd /tmp
wget https://github.com/Kitware/CMake/releases/download/v3.28.3/cmake-3.28.3-linux-x86_64.tar.gz

# 3. 解压到 /opt
sudo tar -zxvf cmake-3.28.3-linux-x86_64.tar.gz -C /opt

#4.将 CMake 目录加入 PATH
echo 'export PATH="/opt/cmake-3.28.3-linux-x86_64/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

#验证
cmake --version

安装脚本

bash 复制代码
#!/bin/bash

# CentOS 7 安装 Poppler 23.08.0 脚本
# 作者:AI助手
# 功能:修复 EOL 仓库问题 + 安装 devtoolset-7 + 编译 Poppler 23.08.0

set -e  # 遇到错误立即退出

echo "=== CentOS 7 Poppler 23.08.0 安装脚本 ==="

# 1. 清理所有 SCL 相关仓库(解决重复定义问题)
echo "1. 清理 SCL 仓库配置..."
sudo rm -f /etc/yum.repos.d/*sclo*
sudo rm -f /etc/yum.repos.d/*scl*

# 2. 创建 Vault 源(主仓库)
echo "2. 配置 CentOS Vault 源..."
cat > /etc/yum.repos.d/CentOS-Base.repo <<'EOF'
[base]
name=CentOS-$releasever - Base
baseurl=https://vault.centos.org/7.9.2009/os/$basearch/
gpgcheck=1
gpgkey=https://vault.centos.org/7.9.2009/os/x86_64/RPM-GPG-KEY-CentOS-7
enabled=1

[updates]
name=CentOS-$releasever - Updates
baseurl=https://vault.centos.org/7.9.2009/updates/$basearch/
gpgcheck=1
gpgkey=https://vault.centos.org/7.9.2009/updates/x86_64/RPM-GPG-KEY-CentOS-7
enabled=1

[extras]
name=CentOS-$releasever - Extras
baseurl=https://vault.centos.org/7.9.2009/extras/$basearch/
gpgcheck=1
gpgkey=https://vault.centos.org/7.9.2009/extras/x86_64/RPM-GPG-KEY-CentOS-7
enabled=1
EOF

# 3. 创建 SCL 仓库(仅 rh,不含 sclo)
cat > /etc/yum.repos.d/CentOS-SCL.repo <<'EOF'
[centos-sclo-rh]
name=CentOS-7 - SCLo rh
baseurl=https://vault.centos.org/7.9.2009/sclo/$basearch/rh/
enabled=1
gpgcheck=0
EOF

# 4. 清理 yum 缓存
echo "3. 清理 yum 缓存..."
sudo yum clean all
sudo rm -rf /var/cache/yum

# 5. 测试 yum 是否正常
echo "4. 测试 yum 配置..."
sudo yum makecache

# 6. 安装编译依赖
echo "5. 安装编译依赖..."
sudo yum install -y \
    gcc gcc-c++ make cmake \
    libjpeg-devel libpng-devel libtiff-devel \
    freetype-devel fontconfig-devel cairo-devel \
    glib2-devel openjpeg2-devel boost-devel \
    zlib-devel

# 7. 安装 devtoolset-7(GCC 7.3.1,支持 C++17)
echo "6. 安装 devtoolset-7..."
sudo yum install -y devtoolset-7-gcc-c++

# 8. 下载并编译 Freetype 2.13.2(Poppler 23.08 要求 ≥2.11)
echo "7. 编译安装 Freetype 2.13.2..."
cd /tmp
wget https://download.savannah.gnu.org/releases/freetype/freetype-2.13.2.tar.xz
tar -xf freetype-2.13.2.tar.xz
cd freetype-2.13.2
./configure --prefix=/usr/local --enable-freetype-config
make -j$(nproc)
sudo make install
export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH"

# 9. 下载 Poppler 23.08.0
echo "8. 下载 Poppler 23.08.0..."
cd /tmp
if [ ! -d "poppler-23.08.0" ]; then
    wget https://poppler.freedesktop.org/poppler-23.08.0.tar.xz
    tar -xf poppler-23.08.0.tar.xz
fi

# 10. 编译 Poppler(在 devtoolset-7 环境下)
echo "9. 编译 Poppler 23.08.0..."
cd poppler-23.08.0

# 启用 devtoolset-7 并编译
scl enable devtoolset-7 bash << 'EOF_INNER'
cd /tmp/poppler-23.08.0
rm -rf build
mkdir build && cd build

cmake .. \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_INSTALL_PREFIX=/usr/local \
    -DENABLE_UNSTABLE_API_ABI_HEADERS=ON \
    -DENABLE_QT5=OFF \
    -DENABLE_QT6=OFF \
    -DENABLE_GLIB=ON \
    -DENABLE_CPP=ON \
    -DENABLE_LIBOPENJPEG=openjpeg2 \
    -DENABLE_NSS3=OFF \
    -DENABLE_GPGME=OFF \
    -DENABLE_LIBTIFF=OFF \
    -DENABLE_BOOST=OFF

make -j$(nproc)
sudo make install
EOF_INNER

# 11. 更新动态库缓存
echo "10. 更新动态库缓存..."
sudo ldconfig

# 12. 验证安装
echo "11. 验证安装..."
/usr/local/bin/pdftotext -v

echo "=== 安装完成! ==="
echo "pdftotext 已安装到 /usr/local/bin/pdftotext"
echo "版本信息如上所示"
echo "如需在脚本中使用,请确保 PATH 包含 /usr/local/bin"
3. 基本使用
Bash 复制代码
# 提取文本到 stdout(终端直接显示)
pdftotext -layout -enc UTF-8 example.pdf -

# 提取到文件
pdftotext -layout example.pdf output.txt

常用参数:

  • -layout:尽量保留原始布局(多栏、表格对齐更准确)
  • -enc UTF-8:指定输出编码(避免中文乱码)
  • -:表示输出到标准输出(stdout)

Windows 系统

⚠️ Windows 官方不提供 Poppler,需使用第三方编译版本。

1. 下载 Poppler for Windows

推荐使用社区维护的预编译版本:

🔗 官方 GitHub 发布页(推荐):

https://github.com/oschwartz10612/poppler-windows/releases

👉 下载最新版 .zip 文件(如 poppler-xx.xx.x_x64.7z 或 .zip)

2. 安装步骤
  • 解压下载的压缩包(例如到 C:\poppler)
  • 进入 bin 目录,确认存在 pdftotext.exe
  • 将 C:\poppler\bin 添加到系统环境变量 PATH 中:
    • 右键"此电脑" → "属性" → "高级系统设置" → "环境变量"
    • 在"系统变量"中找到 Path,点击"编辑"
    • 新增一行:C:\poppler\bin(根据你的实际路径修改)
  • 重启命令提示符(CMD)或 PowerShell
3. 验证安装

打开 CMD 或 PowerShell,运行:

Cmd 复制代码
pdftotext -v

应显示版本信息。

4. 基本使用(CMD / PowerShell)
Cmd 复制代码
:: 输出到控制台(注意末尾的 "-")
pdftotext -layout -enc UTF-8 example.pdf -

:: 输出到文件
pdftotext -layout example.pdf output.txt

💡 提示:Windows 默认编码为 GBK,若 PDF 含中文,建议始终加上 -enc UTF-8 并用支持 UTF-8 的编辑器(如 VS Code)查看输出。

三、工具类

Java 复制代码
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 使用系统 pdftotext 命令提取 PDF 文本内容的工具类
 * 需要系统已安装 Poppler(包含 pdftotext)
 */
public class PdfToTextUtil {

    /**
     * 从 PDF 文件中提取文本(保留布局)
     *
     * @param pdfFile PDF 文件路径
     * @return 提取的文本内容(UTF-8 字符串)
     * @throws IOException 当 PDF 文件不存在、pdftotext 未安装或执行失败时抛出
     */
    public static String extractText(String pdfFile) throws IOException {
        return extractText(new File(pdfFile));
    }

    /**
     * 从 PDF 文件中提取文本(保留布局)
     *
     * @param pdfFile PDF 文件对象
     * @return 提取的文本内容(UTF-8 字符串)
     * @throws IOException 当 PDF 文件不存在、pdftotext 未安装或执行失败时抛出
     */
    public static String extractText(File pdfFile) throws IOException {
        if (!pdfFile.exists() || !pdfFile.isFile()) {
            throw new FileNotFoundException("PDF file not found: " + pdfFile.getAbsolutePath());
        }

        // 获取 pdftotext 执行路径(优先从系统属性获取)
        String pdftotextPath = System.getProperty("pdftotext.path", "pdftotext");

        // 构建命令:pdftotext -layout -enc UTF-8 input.pdf -
        List<String> command = new ArrayList<>();
        command.add(pdftotextPath);
        command.add("-layout");       // 保留原始布局(列、对齐等)
        command.add("-enc");          // 指定输出编码
        command.add("UTF-8");
        command.add(pdfFile.getAbsolutePath());
        command.add("-");             // 输出到 stdout

        ProcessBuilder pb = new ProcessBuilder(command);
        pb.redirectErrorStream(true); // 合并 stderr 到 stdout

        Process process = pb.start();

        StringBuilder output = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) {
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line).append(System.lineSeparator());
            }
        }

        try {
            boolean finished = process.waitFor(30, TimeUnit.SECONDS); // 设置最大等待时间为30秒
            if (!finished) {
                process.destroyForcibly();
                throw new IOException("pdftotext process timed out and was forcibly terminated.");
            }
            int exitCode = process.exitValue();
            if (exitCode != 0) {
                // 注意:不要把整个 output 放进异常信息中以防泄露敏感内容
                throw new IOException("pdftotext failed with exit code " + exitCode);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IOException("pdftotext process interrupted", e);
        }

        return output.toString();
    }

    // ===== 示例用法 =====
    public static void main(String[] args) {
        try {
            String text = PdfToTextUtil.extractText("D:002.pdf");
            System.out.println(text);
        } catch (IOException e) {
            System.err.println("Error extracting PDF text: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

运行截图:

四、常见问题

问题 解决方案
pdftotext: command not found Linux:未安装;Windows:未配置 PATH
中文乱码 始终使用 -enc UTF-8,Java 读取时指定 UTF-8 编码
提取结果为空 PDF 可能是扫描件(图像),需用 OCR(如 Tess4J)
GPL 合规担忧 仅调用命令行通常不构成"衍生作品",但建议咨询法务
相关推荐
humors2217 小时前
pdf工具分享
pdf·工具·程序·网站·转换·处理
新缸中之脑13 小时前
用MonkeyOCR解析复杂PDF
pdf
tiantangzhixia1 天前
Master PDF Linux 平台的 5.9.35 版本安装与自用
linux·pdf·master pdf
开开心心就好2 天前
发票合并打印工具,多页布局设置实时预览
linux·运维·服务器·windows·pdf·harmonyos·1024程序员节
软件工程小施同学2 天前
区块链论文速读 CCF A--VLDB 2025 (1) 附pdf下载
pdf·区块链
Java面试题总结4 天前
基于 Java 的 PDF 文本水印实现方案(iText7 示例)
java·python·pdf
傻啦嘿哟4 天前
Python操作PDF页面详解:删除指定页的完整方案
开发语言·python·pdf
m5655bj4 天前
使用 C# 修改 PDF 页面尺寸
java·pdf·c#
geovindu4 天前
python: 简单提取PDF文档内文字
开发语言·python·pdf
m0_694845574 天前
HandBrake 是什么?视频转码工具使用与服务器部署教程
服务器·前端·pdf·开源·github·音视频