Java自動(dòng)化提取PDF表格的全場(chǎng)景實(shí)現(xiàn)
隨著企業(yè)數(shù)據(jù)自動(dòng)化的需求日益激增,提取 PDF 中的表格的需求也越來(lái)越受到重視。盡管此前我們就發(fā)布過(guò)使用 Java 提取 PDF 中的表格,并保存為 Text 文件的教程,但顯然,簡(jiǎn)單的文本提取難以滿足復(fù)雜的數(shù)據(jù)分析場(chǎng)景。
在處理財(cái)務(wù)報(bào)表、供應(yīng)鏈清單等結(jié)構(gòu)化文檔時(shí),開發(fā)者不僅需要獲取數(shù)據(jù),更需要保留其邏輯結(jié)構(gòu)。本文將基于最新的 Spire.PDF for Java,展示如何精準(zhǔn)地將 PDF 表格轉(zhuǎn)換為文本、CSV 以及 Excel 格式,實(shí)現(xiàn)全場(chǎng)景的數(shù)據(jù)自動(dòng)化提取。
環(huán)境準(zhǔn)備
在進(jìn)入今天的正文前,請(qǐng)確保你的開發(fā)環(huán)境已就緒:
- JDK 支持:推薦使用 JDK 8 及以上版本。
- Maven 依賴:在
pom.xml文件中配置以下倉(cāng)庫(kù)和依賴,以獲取最新的組件支持。
<repositories>
<repository>
<id>com.e-iceblue</id>
<name>e-iceblue</name>
<url>https://repo.e-iceblue.cn/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.pdf</artifactId>
<version>11.12.16</version>
</dependency>
</dependencies>
或?qū)Ш降?Spire.PDF for Java 的官方網(wǎng)站下載安裝包,解壓后將 jar 文件手動(dòng)導(dǎo)入到項(xiàng)目中。
基礎(chǔ)提?。簩?PDF 表格轉(zhuǎn)為文本
作為入門級(jí)方案,將 PDF 中的表格提取為文本適用于對(duì)格式要求不高、僅需獲取原始信息的場(chǎng)景。
技術(shù)邏輯:利用 PdfTableExtractor 識(shí)別表格,通過(guò)遍歷單元格獲取字符串。
import com.spire.pdf.*;
import com.spire.pdf.utilities.PdfTable;
import com.spire.pdf.utilities.PdfTableExtractor;
import java.io.FileWriter;
import java.io.IOException;
public class ExtractTable {
public static void main(String[] args)throws IOException {
// 實(shí)例化PdfDocument類的對(duì)象
PdfDocument pdf = new PdfDocument();
// 加載PDF文檔
pdf.loadFromFile("E:/Administrator/Python1/input/項(xiàng)目進(jìn)度.pdf");
// 創(chuàng)建StringBuilder類的實(shí)例
StringBuilder builder = new StringBuilder();
// 創(chuàng)建PdfTableExtractor類的對(duì)象
PdfTableExtractor extractor = new PdfTableExtractor(pdf);
// 遍歷每一頁(yè)
for (int page = 0; page < pdf.getPages().getCount(); page++)
{
// 提取頁(yè)面中的表格存入PdfTable[]數(shù)組
PdfTable[] tableLists = extractor.extractTable(page);
if (tableLists != null && tableLists.length > 0)
{
//遍歷表格
for (PdfTable table : tableLists)
{
int row = table.getRowCount();//獲取表格行
int column = table.getColumnCount();//獲取表格列
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
// 獲取表格中的文本內(nèi)容
String text = table.getText(i, j);
// 將獲取的text寫入StringBuilder容器
builder.append(text+" ");
}
builder.append("\r\n");
}
}
}
}
// 保存為txt文檔
FileWriter fileWriter = new FileWriter("E:/Administrator/Python1/output/提取表格為文本.txt");
fileWriter.write(builder.toString());
fileWriter.flush();
fileWriter.close();
}
}
源文件與輸出文件對(duì)比圖:

方案一:最簡(jiǎn)化提取——將 PDF 表格導(dǎo)出為 CSV
雖然保存為文本格式能夠快速獲取內(nèi)容,但在面對(duì)需要二次計(jì)算或數(shù)據(jù)入庫(kù)的場(chǎng)景時(shí),將 PDF 表格導(dǎo)出為 CSV 是一種更合適的選擇。CSV 格式通用性很高,幾乎可以被所有的主流數(shù)據(jù)庫(kù)系統(tǒng)、數(shù)據(jù)分析工具以及編程語(yǔ)言無(wú)差識(shí)別,是構(gòu)建自動(dòng)化數(shù)據(jù)流轉(zhuǎn)鏈路的理想中間格式。它不僅寫入速度極快,且內(nèi)存開銷低,尤其適合后端批量處理任務(wù)。
技術(shù)邏輯:CSV(逗號(hào)分隔值)是結(jié)構(gòu)化數(shù)據(jù)的標(biāo)準(zhǔn)格式。我們通過(guò) PdfTableExtractor 獲取表格數(shù)據(jù)后,通過(guò)代碼控制逗號(hào)分隔符輸出。
import com.spire.pdf.*;
import com.spire.pdf.utilities.*;
import java.io.*;
public class ExtractTable {
public static void main(String[] args) throws Exception {
// 1. 加載 PDF 文檔
PdfDocument pdf = new PdfDocument();
// 請(qǐng)確保路徑正確
pdf.loadFromFile("E:/Administrator/Python1/input/項(xiàng)目進(jìn)度.pdf");
// 用于存儲(chǔ)提取文本的 StringBuilder StringBuilder sb = new StringBuilder();
// 2. 遍歷每一頁(yè)并提取表格
for (int i = 0; i < pdf.getPages().getCount(); i++) {
PdfTableExtractor extractor = new PdfTableExtractor(pdf);
PdfTable[] tableLists = extractor.extractTable(i);
if (tableLists != null) {
for (PdfTable table : tableLists) {
for (int row = 0; row < table.getRowCount(); row++) {
for (int col = 0; col < table.getColumnCount(); col++) {
// 使用工具方法處理 CSV 特殊字符和換行
String cellText = escapeCsvField(table.getText(row, col));
sb.append(cellText);
// 列之間用逗號(hào)分隔
if (col < table.getColumnCount() - 1) {
sb.append(",");
}
}
// 行之間用換行符分隔
sb.append("\n");
}
}
}
}
// 3. 寫入帶 BOM 的 CSV 文件
File outFile = new File("E:/Administrator/Python1/output/提取表格為csv.csv");
// 確保輸出目錄存在
if (!outFile.getParentFile().exists()) {
outFile.getParentFile().mkdirs();
}
try (FileOutputStream fos = new FileOutputStream(outFile)) {
// 【核心修復(fù)】寫入 UTF-8 BOM 字節(jié),防止 Excel 打開亂碼
fos.write(0xEF);
fos.write(0xBB);
fos.write(0xBF);
// 使用 UTF-8 編碼包裝輸出流
try (Writer writer = new OutputStreamWriter(fos, "UTF-8")) {
writer.write(sb.toString());
}
}
pdf.close();
System.out.println("PDF 表格已成功導(dǎo)出為 CSV 文件。");
}
/**
* 處理 CSV 字段的工具方法:
* 1. 去除單元格內(nèi)的換行符
* 2. 轉(zhuǎn)義雙引號(hào)
* 3. 對(duì)包含特殊字符的字段添加雙引號(hào)包裹
*/
private static String escapeCsvField(String text) {
if (text == null) return "";
// 去掉單元格內(nèi)的換行符(防止破壞 CSV 行結(jié)構(gòu))
text = text.replaceAll("[\\n\\r]", " ");
// 處理特殊字符
boolean containsSpecialChar = text.contains(",") || text.contains(";") ||
text.contains("\"") || text.contains("\n");
if (containsSpecialChar) {
// 轉(zhuǎn)義雙引號(hào):將 " 替換為 "" text = text.replace("\"", "\"\"");
// 整個(gè)字段用雙引號(hào)包裹
text = "\"" + text + "\"";
}
return text.trim();
}
}
結(jié)果文件示意圖:

提示:在導(dǎo)出 CSV 時(shí),建議對(duì)單元格內(nèi)容使用雙引號(hào)包裹,以處理數(shù)據(jù)本身含有逗號(hào)的情況。此外,確保文件使用 UTF-8 (with BOM) 編碼,防止在 Excel 中直接打開時(shí)出現(xiàn)中文亂碼。
方案二:結(jié)構(gòu)化導(dǎo)出——將 PDF 表格直接轉(zhuǎn)為 Excel
由于 CSV 只能存儲(chǔ)純文本,合并單元格、字體等格式在導(dǎo)出時(shí)會(huì)丟失。如果需要保留樣式,應(yīng)該選擇將 PDF 中的表格提取為 Excel 文件。比如說(shuō)處理財(cái)務(wù)報(bào)表、審計(jì)清單等文件,單元格樣式與數(shù)據(jù)息息相關(guān)。通過(guò)導(dǎo)出為 Excel,你可以更好地保留原 PDF 文檔中的布局,避免對(duì)數(shù)據(jù)進(jìn)行二次加工。
核心步驟:
- 加載源 PDF 文檔。
- 遍歷讀取 PDF 中的表格單元格和數(shù)據(jù)。
- 將數(shù)據(jù)填入 Excel 單元格中。
- 設(shè)置 Excel 單元格(可選步驟)。
- 調(diào)用
saveToFile并指定FileFormat.XLSX。
import com.spire.pdf.PdfDocument;
import com.spire.pdf.utilities.PdfTable;
import com.spire.pdf.utilities.PdfTableExtractor;
import com.spire.xls.ExcelVersion;
import com.spire.xls.Workbook;
import com.spire.xls.Worksheet;
public class ExtractTable {
public static void main(String[] args) {
//加載示例PDF文檔
PdfDocument pdf = new PdfDocument("E:/Administrator/Python1/input/項(xiàng)目進(jìn)度.pdf");
//創(chuàng)建一個(gè)PdfTableExtractor實(shí)例
PdfTableExtractor extractor = new PdfTableExtractor(pdf);
//從第一頁(yè)提取表格
PdfTable[] pdfTables = extractor.extractTable(0);
//創(chuàng)建一個(gè)工作簿對(duì)象
Workbook wb = new Workbook();
//刪除默認(rèn)工作表
wb.getWorksheets().clear();
//如果找到任何表格
if (pdfTables != null && pdfTables.length > 0) {
//循環(huán)遍歷表格
for (int tableNum = 0; tableNum < pdfTables.length; tableNum++) {
//將工作表添加到工作簿
String sheetName = String.format("Table - %d", tableNum + 1);
Worksheet sheet = wb.getWorksheets().add(sheetName);
//循環(huán)遍歷當(dāng)前表格中的行
for (int rowNum = 0; rowNum < pdfTables[tableNum].getRowCount(); rowNum++) {
//循環(huán)遍歷當(dāng)前表格中的列
for (int colNum = 0; colNum < pdfTables[tableNum].getColumnCount(); colNum++) {
//從當(dāng)前表格單元格中提取數(shù)據(jù)
String text = pdfTables[tableNum].getText(rowNum, colNum);
//將數(shù)據(jù)插入特定單元格
sheet.get(rowNum + 1, colNum + 1).setText(text);
}
}
//自動(dòng)調(diào)整列寬
for (int sheetColNum = 0; sheetColNum < sheet.getColumns().length; sheetColNum++) {
sheet.autoFitColumn(sheetColNum + 1);
}
}
}
//將工作簿保存為 Excel 文件
wb.saveToFile("E:/Administrator/Python1/output/提取表格為excel.xlsx", ExcelVersion.Version2016);
}
}
效果展示:

進(jìn)階挑戰(zhàn):處理復(fù)雜的跨頁(yè)提取
在實(shí)際業(yè)務(wù)中,我們常遇到長(zhǎng)篇合同或大型清單,同一個(gè)表格被拆分到兩個(gè)或多個(gè)物理頁(yè)面。這種情況單純依靠循環(huán)提取會(huì)導(dǎo)致數(shù)據(jù)斷層。那么如何識(shí)別第二頁(yè)頂部的表格是第一頁(yè)末尾表格的延續(xù)?如何自動(dòng)合并表頭?
針對(duì)此類涉及坐標(biāo)邏輯判斷的高階需求,我們準(zhǔn)備了詳細(xì)的進(jìn)階教程。感興趣的話可以查看官網(wǎng)教程如何在 Java 中將 PDF 轉(zhuǎn)換為 CSV(輕松提取 PDF 表格)
總結(jié)與技術(shù)支持
從提取 PDF 表格為文本,到涵蓋 CSV 和 Excel 的全場(chǎng)景導(dǎo)出,技術(shù)工具的演進(jìn)讓 PDF 數(shù)據(jù)處理變得不再繁瑣。通過(guò) Spire.PDF for Java,你可以根據(jù)業(yè)務(wù)需求靈活選擇輕量級(jí)的 CSV 方案或高保真的 Excel 方案。
到此這篇關(guān)于Java自動(dòng)化提取PDF表格的全場(chǎng)景實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java提取PDF表格內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java compare compareTo方法區(qū)別詳解
本文主要介紹了java compare compareTo方法區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
SpringMVC對(duì)日期類型的轉(zhuǎn)換示例
本篇文章主要介紹了SpringMVC對(duì)日期類型的轉(zhuǎn)換示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02
JVM內(nèi)存結(jié)構(gòu)劃分實(shí)例解析
這篇文章主要介紹了JVM內(nèi)存結(jié)構(gòu)劃分實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
idea設(shè)置@Author文件頭注釋的實(shí)現(xiàn)步驟
本文主要介紹了idea設(shè)置@Author文件頭注釋的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
IntelliJ IDEA右鍵文件夾沒(méi)有Java Class文件的原因及解決方法
這篇文章主要介紹了IntelliJ IDEA右鍵文件夾沒(méi)有Java Class文件的原因及解決方法,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
使用SpringBoot+InfluxDB實(shí)現(xiàn)高效數(shù)據(jù)存儲(chǔ)與查詢
InfluxDB 是一個(gè)開源的時(shí)間序列數(shù)據(jù)庫(kù),特別適合處理帶有時(shí)間戳的監(jiān)控?cái)?shù)據(jù)、指標(biāo)數(shù)據(jù)等,下面詳細(xì)介紹如何在 Spring Boot 項(xiàng)目中集成 InfluxDB 實(shí)現(xiàn)高效數(shù)據(jù)存儲(chǔ)與查詢功能,需要的朋友可以參考下2025-08-08
RocketMQ?消息Message的結(jié)構(gòu)和使用方式詳解
Message是RocketMQ的數(shù)據(jù)包,它不僅是業(yè)務(wù)數(shù)據(jù)的載體,更是路由、過(guò)濾、追蹤、延遲、事務(wù)等功能的基礎(chǔ),掌握Message,你就掌握了RocketMQ的語(yǔ)言,本文給大家介紹什么是?Message及理解Message的結(jié)構(gòu)、屬性、生命周期和使用方式,感興趣的朋友一起看看吧2025-08-08
Java+EasyExcel實(shí)現(xiàn)文件上傳功能
這篇文章主要為大家詳細(xì)介紹了如何通過(guò)Java和EasyExcel實(shí)現(xiàn)文件上傳功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-02-02
SpringMVC使用自定義驗(yàn)證器進(jìn)行數(shù)據(jù)驗(yàn)證的方法
SpringMVC?提供了強(qiáng)大的數(shù)據(jù)驗(yàn)證機(jī)制,可以方便地驗(yàn)證表單提交的數(shù)據(jù),除了自帶的驗(yàn)證器之外,SpringMVC?還支持自定義驗(yàn)證器,允許開發(fā)者根據(jù)業(yè)務(wù)需求自定義驗(yàn)證規(guī)則,本文將介紹如何在?SpringMVC?中使用自定義驗(yàn)證器2023-07-07
Java Socket設(shè)置timeout的幾種常用方式說(shuō)明
這篇文章主要介紹了Java Socket設(shè)置timeout的幾種常用方式說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11

