Java輕松提取PDF表格數(shù)據(jù)并轉(zhuǎn)換為CSV
在日常工作中,你是否曾為從 PDF 中手動(dòng)復(fù)制粘貼表格數(shù)據(jù)而抓狂?面對(duì)那些包含財(cái)務(wù)報(bào)表、物流清單、統(tǒng)計(jì)報(bào)告或各種數(shù)據(jù)清單的 PDF 文件,你是否也曾想過(guò),如果能自動(dòng)化地將這些表格數(shù)據(jù)提取出來(lái),并轉(zhuǎn)換為易于處理的 CSV 格式,那該多好?
今天,我就來(lái)為大家揭秘如何在 Java 中實(shí)現(xiàn)這一目標(biāo),告別繁瑣的手動(dòng)操作,輕松高效地將 PDF 表格數(shù)據(jù)轉(zhuǎn)換為 CSV。
為什么我們需要從 PDF 中提取表格數(shù)據(jù)
PDF 格式因其出色的跨平臺(tái)兼容性和視覺(jué)保真度,被廣泛應(yīng)用于文檔共享和歸檔。然而,它的優(yōu)勢(shì)也恰恰是其在數(shù)據(jù)處理方面的局限:
- 難以直接編輯和分析: PDF 旨在作為“電子紙”,其內(nèi)容通常是固定的,難以直接修改或進(jìn)行數(shù)據(jù)分析。
- 數(shù)據(jù)孤島: 重要的表格數(shù)據(jù)被“鎖定”在 PDF 中,無(wú)法直接導(dǎo)入數(shù)據(jù)庫(kù)、電子表格或其他業(yè)務(wù)系統(tǒng)進(jìn)行進(jìn)一步處理。
將 PDF 表格數(shù)據(jù)轉(zhuǎn)換為 CSV (Comma Separated Values) 格式,則能帶來(lái)諸多便利:
- 數(shù)據(jù)分析友好: CSV 是一種純文本格式,易于導(dǎo)入 Excel、Google Sheets 或各種數(shù)據(jù)分析工具進(jìn)行統(tǒng)計(jì)、篩選和可視化。
- 系統(tǒng)集成: 方便將數(shù)據(jù)導(dǎo)入數(shù)據(jù)庫(kù)、CRM、ERP 等系統(tǒng),實(shí)現(xiàn)數(shù)據(jù)共享和業(yè)務(wù)流程自動(dòng)化。
- 減少錯(cuò)誤: 自動(dòng)化提取避免了手動(dòng)復(fù)制粘貼可能引入的錯(cuò)誤,確保數(shù)據(jù)準(zhǔn)確性。
因此,掌握 PDF 表格的自動(dòng)化提取技術(shù),對(duì)于提升數(shù)據(jù)處理效率和業(yè)務(wù)自動(dòng)化水平至關(guān)重要。
借助 Spire.PDF for Java 實(shí)現(xiàn) PDF 到 CSV 的高效轉(zhuǎn)換
Spire.PDF for Java 是一款功能全面、性能卓越的 Java PDF 處理庫(kù)。它提供了豐富的 API,用于創(chuàng)建、編輯、轉(zhuǎn)換、打印和渲染 PDF 文檔。尤其在 PDF 表格提取方面,Spire.PDF for Java 能夠智能識(shí)別 PDF 中的表格結(jié)構(gòu),并以結(jié)構(gòu)化的方式返回?cái)?shù)據(jù),極大地簡(jiǎn)化了開發(fā)難度。
下面,我們來(lái)詳細(xì)分解如何使用它來(lái)完成 PDF 到 CSV 的轉(zhuǎn)換:
環(huán)境準(zhǔn)備:引入 Spire.PDF for Java 依賴
首先,你需要在你的 Maven 或 Gradle 項(xiàng)目中引入 Spire.PDF for Java 依賴。
Maven:
<repositories>
<repository>
<id>e-iceblue</id>
<url>https://repo.e-iceblue.cn/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.pdf</artifactId>
<version>10.X.X</version> <!-- 請(qǐng)?zhí)鎿Q為最新版本號(hào) -->
</dependency>
</dependencies>
Gradle:
repositories {
maven { url 'https://repo.e-iceblue.cn/repository/maven-public/' }
}
dependencies {
implementation 'e-iceblue:spire.pdf:10.X.X' // 請(qǐng)?zhí)鎿Q為最新版本號(hào)
}
請(qǐng)?jiān)L問(wèn) Spire.PDF for Java 官網(wǎng)獲取最新的版本號(hào)。
核心步驟分解與代碼示例
現(xiàn)在,我們來(lái)看具體的代碼實(shí)現(xiàn)。假設(shè)我們有一個(gè)名為 tableSample.pdf 的 PDF 文件,其中包含我們需要提取的表格數(shù)據(jù)。
import com.spire.pdf.PdfDocument;
import com.spire.pdf.utilities.PdfTable;
import com.spire.pdf.utilities.PdfTableExtractor;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
public class PdfTableToCsvConverter {
public static void main(String[] args) {
// 1. 加載 PDF 文檔
String pdfFilePath = "data/tableSample.pdf"; // 替換為你的 PDF 文件路徑
String csvOutputFilePath = "output/extracted_table.csv"; // CSV 輸出路徑
PdfDocument pdfDocument = new PdfDocument();
try {
pdfDocument.loadFromFile(pdfFilePath);
System.out.println("PDF 文檔加載成功:" + pdfFilePath);
// 2. 創(chuàng)建 PdfTableExtractor 實(shí)例
PdfTableExtractor extractor = new PdfTableExtractor(pdfDocument);
// 使用 FileWriter 寫入 CSV 文件
try (FileWriter csvWriter = new FileWriter(csvOutputFilePath)) {
// 遍歷 PDF 的每一頁(yè)
for (int pageIndex = 0; pageIndex < pdfDocument.getPages().getCount(); pageIndex++) {
System.out.println("正在處理第 " + (pageIndex + 1) + " 頁(yè)...");
// 3. 識(shí)別并提取表格
// extractTable(int pageIndex) 方法返回當(dāng)前頁(yè)的所有表格
PdfTable[] tableLists = extractor.extractTable(pageIndex);
if (tableLists != null && tableLists.length > 0) {
for (PdfTable table : tableLists) {
System.out.println(" 發(fā)現(xiàn)表格,行數(shù):" + table.getRowCount() + ", 列數(shù):" + table.getColumnCount());
// 4. 將提取到的數(shù)據(jù)寫入 CSV
for (int row = 0; row < table.getRowCount(); row++) {
StringBuilder rowData = new StringBuilder();
for (int column = 0; column < table.getColumnCount(); column++) {
// 獲取單元格文本
String cellText = table.getText(row, column);
// 對(duì)包含逗號(hào)或雙引號(hào)的文本進(jìn)行處理,避免 CSV 格式錯(cuò)誤
if (cellText.contains(",") || cellText.contains(""")) {
cellText = """ + cellText.replace(""", """") + """;
}
rowData.append(cellText);
if (column < table.getColumnCount() - 1) {
rowData.append(","); // 添加逗號(hào)分隔
}
}
csvWriter.append(rowData.toString()).append("\n"); // 寫入一行數(shù)據(jù)并換行
}
// 每個(gè)表格之間可以添加一個(gè)空行,或者其他分隔符,以便區(qū)分
csvWriter.append("\n");
}
} else {
System.out.println(" 第 " + (pageIndex + 1) + " 頁(yè)未檢測(cè)到表格。");
}
}
System.out.println("數(shù)據(jù)已成功提取并保存到:" + csvOutputFilePath);
} catch (IOException e) {
System.err.println("寫入 CSV 文件時(shí)發(fā)生錯(cuò)誤:" + e.getMessage());
}
} catch (Exception e) {
System.err.println("處理 PDF 文件時(shí)發(fā)生錯(cuò)誤:" + e.getMessage());
e.printStackTrace();
} finally {
if (pdfDocument != null) {
pdfDocument.close(); // 關(guān)閉文檔,釋放資源
pdfDocument.dispose();
}
}
}
}
代碼說(shuō)明:
PdfDocument.loadFromFile(): 用于加載指定的 PDF 文件。PdfTableExtractor: Spire.PDF for Java 提供的表格提取工具類。extractor.extractTable(pageIndex): 這是核心方法,它會(huì)智能分析指定頁(yè)面的內(nèi)容,識(shí)別出其中的表格結(jié)構(gòu),并返回一個(gè)PdfTable數(shù)組。PdfTable.getRowCount()和PdfTable.getColumnCount(): 獲取提取到表格的行數(shù)和列數(shù)。PdfTable.getText(row, column): 獲取指定單元格的文本內(nèi)容。- CSV 格式化: 代碼中包含了簡(jiǎn)單的 CSV 格式化邏輯,特別是針對(duì)含有逗號(hào)或雙引號(hào)的單元格內(nèi)容,使用雙引號(hào)包裹并對(duì)內(nèi)部雙引號(hào)進(jìn)行轉(zhuǎn)義,以確保生成的 CSV 文件格式正確。
運(yùn)行上述代碼,你就可以將 tableSample.pdf 中的所有表格數(shù)據(jù)提取出來(lái),并保存到 extracted_table.csv 文件中。
深入優(yōu)化與注意事項(xiàng)
盡管 Spire.PDF for Java 已經(jīng)非常強(qiáng)大,但在實(shí)際應(yīng)用中,我們?nèi)孕杩紤]一些優(yōu)化和注意事項(xiàng):
復(fù)雜表格處理
合并單元格與跨頁(yè)表格: Spire.PDF for Java 通常能較好地處理合并單元格和跨頁(yè)表格。對(duì)于跨頁(yè)表格,它會(huì)嘗試在不同頁(yè)面上識(shí)別出表格的各個(gè)部分。如果遇到識(shí)別不準(zhǔn)確的情況,可能需要結(jié)合其他文本提取功能,或者進(jìn)行二次數(shù)據(jù)清洗。
非標(biāo)準(zhǔn)表格: 對(duì)于那些并非嚴(yán)格意義上的表格(例如,僅通過(guò)線條或文本排版模擬的表格),Spire.PDF for Java 的智能識(shí)別可能無(wú)法完全捕捉。在這種情況下,你可能需要結(jié)合 PdfTextFinder 等工具,通過(guò)文本定位和正則表達(dá)式來(lái)提取數(shù)據(jù),然后手動(dòng)構(gòu)建表格結(jié)構(gòu)。
性能考量
大型 PDF 文件: 處理包含數(shù)百上千頁(yè)的大型 PDF 文件時(shí),內(nèi)存消耗和處理時(shí)間可能會(huì)增加。建議:
- 分批處理: 如果可能,將大型 PDF 文件拆分為多個(gè)小文件進(jìn)行處理。
- 優(yōu)化循環(huán): 確保在循環(huán)中沒(méi)有進(jìn)行不必要的對(duì)象創(chuàng)建或復(fù)雜計(jì)算。
- 及時(shí)釋放資源: 始終在
finally塊中調(diào)用pdfDocument.close()和pdfDocument.dispose()來(lái)釋放資源。
數(shù)據(jù)清洗與驗(yàn)證
- 數(shù)據(jù)質(zhì)量: 即使是智能提取,也可能因?yàn)?PDF 文件的質(zhì)量(如掃描件、低分辨率)導(dǎo)致提取到的數(shù)據(jù)不完全干凈。在將數(shù)據(jù)導(dǎo)入最終系統(tǒng)之前,務(wù)必進(jìn)行數(shù)據(jù)清洗(去除多余空格、統(tǒng)一格式等)和驗(yàn)證。
- 頭部信息: 提取到的表格可能不包含明確的列頭。你可能需要根據(jù)業(yè)務(wù)邏輯,在生成 CSV 文件時(shí)手動(dòng)添加列頭,或者通過(guò)分析第一行數(shù)據(jù)來(lái)識(shí)別列頭。
其他功能延伸
Spire.PDF for Java 不僅僅局限于表格提取。它還提供了強(qiáng)大的文本提取、圖片提取、內(nèi)容替換、文檔合并/拆分、PDF 到其他格式(如 Word、Excel、圖片)的轉(zhuǎn)換等功能。你可以根據(jù)項(xiàng)目需求,進(jìn)一步探索和利用這些功能,實(shí)現(xiàn)更復(fù)雜的 PDF 處理任務(wù)。
處理復(fù)雜的 PDF 轉(zhuǎn) CSV 場(chǎng)景
實(shí)際應(yīng)用中,PDF 文件常常包含多個(gè)表格、跨多頁(yè),或表格結(jié)構(gòu)不規(guī)則。下面介紹如何應(yīng)對(duì)這些情況。
單頁(yè)包含多個(gè)表格
extractTable(i) 返回的 PdfTable[] 包含該頁(yè)中檢測(cè)到的所有表格,可以將每個(gè)表單獨(dú)保存為不同的 CSV 文件:
for (int i = 0; i < pdf.getPages().getCount(); i++) {
PdfTableExtractor extractor = new PdfTableExtractor(pdf);
PdfTable[] tableLists = extractor.extractTable(i);
if (tableLists != null) {
for (int t = 0; t < tableLists.length; t++) {
PdfTable table = tableLists[t];
StringBuilder tableContent = new StringBuilder();
for (int row = 0; row < table.getRowCount(); row++) {
for (int col = 0; col < table.getColumnCount(); col++) {
tableContent.append(escapeCsvField(table.getText(row, col)));
if (col < table.getColumnCount() - 1) {
tableContent.append(",");
}
}
tableContent.append("\n");
}
try (Writer writer = new OutputStreamWriter(
new FileOutputStream("output/Tables/Table_Page" + i + "_Index" + t + ".csv"), "UTF-8")) {
writer.write(sb.toString());
}
}
}
}跨頁(yè)或大表格
如果表格跨越多頁(yè),可以逐頁(yè)提取并 追加寫入,以避免覆蓋:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < pdf.getPages().getCount(); i++) {
PdfTableExtractor extractor = new PdfTableExtractor(pdf);
PdfTable[] tables = extractor.extractTable(i);
if (tables != null) {
for (PdfTable table : tables) {
for (int row = 0; row < table.getRowCount(); row++) {
for (int col = 0; col < table.getColumnCount(); col++) {
sb.append(escapeCsvField(table.getText(row, col)));
if (col < table.getColumnCount() - 1) sb.append(",");
}
sb.append("\n");
}
}
}
}
FileWriter writer = new FileWriter("MergedTables.csv");
writer.write(sb.toString());
writer.close();格式限制
CSV 只能存儲(chǔ)純文本,像合并單元格、字體、圖片等格式會(huì)丟失。如果需要保留樣式,可以導(dǎo)出為 Excel(.xlsx)。
CSV 特殊字符處理
在寫入 CSV 時(shí),逗號(hào)、分號(hào)、雙引號(hào)、換行等特殊字符可能會(huì)破壞文件結(jié)構(gòu)。 上述 Java 示例中的 escapeCsvField 方法可以去除換行并安全轉(zhuǎn)義。
更復(fù)雜的場(chǎng)景下,可以使用 Spire.XLS for Java,通過(guò)簡(jiǎn)單的 Java 代碼將表格數(shù)據(jù)寫入 Excel,再將 Excel 工作表保存為 CSV,無(wú)需手動(dòng)處理特殊字符。
總結(jié)
通過(guò)本文的介紹,相信你已經(jīng)掌握了如何在 Java 中使用 Spire.PDF for Java 庫(kù)來(lái)高效地將 PDF 表格數(shù)據(jù)轉(zhuǎn)換為 CSV 格式。這款工具憑借其智能的表格識(shí)別能力和簡(jiǎn)潔的 API,極大地簡(jiǎn)化了數(shù)據(jù)提取的復(fù)雜性,幫助開發(fā)者從 PDF 的“數(shù)據(jù)孤島”中解放數(shù)據(jù)價(jià)值。
到此這篇關(guān)于Java輕松提取PDF表格數(shù)據(jù)并轉(zhuǎn)換為CSV的文章就介紹到這了,更多相關(guān)Java PDF轉(zhuǎn)CSV內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
application.yml文件中如何開啟mybatis自動(dòng)駝峰映射
這篇文章主要介紹了application.yml文件中開啟mybatis自動(dòng)駝峰映射的方法,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08
SpringBoot實(shí)現(xiàn)HTTP服務(wù)監(jiān)聽的代碼示例
前后端分離項(xiàng)目中,在調(diào)用接口調(diào)試時(shí)候,我們可以通過(guò)cpolar內(nèi)網(wǎng)穿透將本地服務(wù)端接口模擬公共網(wǎng)絡(luò)環(huán)境遠(yuǎn)程調(diào)用調(diào)試,本次教程我們以Java服務(wù)端接口為例,需要的朋友可以參考下2023-05-05
java四種訪問(wèn)權(quán)限實(shí)例分析
這篇文章主要介紹了java四種訪問(wèn)權(quán)限實(shí)例分析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10
MyBatis自定義映射關(guān)系和關(guān)聯(lián)查詢實(shí)現(xiàn)方法詳解
這篇文章主要介紹了MyBatis自定義映射關(guān)系和關(guān)聯(lián)查詢實(shí)現(xiàn)方法,當(dāng)POJO屬性名與數(shù)據(jù)庫(kù)列名不一致時(shí),需要自定義實(shí)體類和結(jié)果集的映射關(guān)系,在MyBatis注解開發(fā)中,使用@Results定義并使用自定義映射,使用 @ResultMap使用自定義映射2023-04-04
springboot多環(huán)境進(jìn)行動(dòng)態(tài)配置的方法
這篇文章主要介紹了springboot多環(huán)境下如何進(jìn)行動(dòng)態(tài)配置,本文主要分享了如何在springboot的項(xiàng)目中使用多環(huán)境配置,重點(diǎn)是”spring.profiles.active“屬性,需要的朋友可以參考下2022-06-06
如何通過(guò)Kaptcha在Web頁(yè)面生成驗(yàn)證碼
這篇文章主要介紹了如何通過(guò)Kaptcha在Web頁(yè)面生成驗(yàn)證碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
關(guān)于.java編譯成.class?與?.class反編譯成.java問(wèn)題
這篇文章主要介紹了關(guān)于.java編譯成.class?與?.class反編譯成.java問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09

