標籤:
需求:用java分頁提取PDF文本。
PDFBox是一個很好的可以滿足上述需求的開源工具。
1.PDF文檔結構
要解析PDF文本,我們首先要瞭解PDF檔案的結構。
關於PDF文檔,最重要的幾點:
一,PDF文檔內容比較複雜,比如有純文字(可以提取出其中的文字,可以用PDF軟體中的“複製”功能)、圖片(無法使用PDF軟體中的“複製”功能)、表單、視頻、音頻等,總之形式比較複雜;
二,PDF檔案採用二進位流與純文字混合的編碼模式,並且沒有採用 Unicode 等標準字元編碼方式,其字元編碼採用 Adobe 公司內建的編碼錶( CMap),這使得對 PDF 的處理更加困難;
三,PDF有自己的檔案結構:檔案頭,對象集合,交叉參考資料表,結尾(準確地說,這是PDF文檔的物理結構,還有邏輯結構,詳情可以點擊查看這篇博文)。
2.PDFBox是個什麼玩意
- 授權協議: Apache
- 開發語言: Java
- 作業系統: 跨平台
- 官網:http://pdfbox.apache.org/
3.PDFBox能幹啥
- 從PDF提取文本
- 合并PDF文檔
- PDF 文檔加密與解密
- 與Lucene搜尋引擎的整合
- 填充PDF/XFDF表單資料
- 從文字檔建立PDF文檔
- 從PDF頁面建立圖片
- 列印PDF文檔
4.準備工作
再次聲明,本demo功能是提取PDF文本(目前只測試了英文可以提取,中文暫未驗證)。
1) 下載好jar包(3個):
a.fontbox-2.0.0-RC2.jar
b.pdfbox-2.0.0-RC2.jar
c.pdfbox-app-2.0.0-RC2.jar
:進官網一看便知(注意版本)。
2) myeclipse或eclipse。
5.開始編程
建立一個項目,寫入下面的源碼:
1 package com.primeton.pdfbox; 2 3 import java.io.File; 4 import java.io.FileOutputStream; 5 import java.io.OutputStreamWriter; 6 import java.io.Writer; 7 8 import org.apache.pdfbox.pdmodel.PDDocument; 9 import org.apache.pdfbox.text.PDFTextStripper; 10 11 12 /** 13 * PDFBox解析PDF文本實現 14 * @author MrChen 15 * 16 */ 17 18 public class PDFReader { 19 /** 20 * @param args 21 */ 22 public static void main(String[] args) { 23 // TODO Auto-generated method stub 24 PDFReader pdfReader = new PDFReader(); 25 System.out.println("E:\\AndroidStudio.pdf"); 26 try { 27 // 取得E盤下的SpringGuide.pdf的內容 28 System.out.println("開始提取"); 29 File file = new File("E:\\AndroidStudio.pdf"); 30 System.out.println("檔案絕對路徑為:"+file.getAbsolutePath()); 31 pdfReader.readFdf(file); 32 System.out.println("提取結束"); 33 } catch (Exception e) { 34 e.printStackTrace(); 35 } 36 } 37 38 public void readFdf(File pdfFile) throws Exception { 39 // 是否排序 40 boolean sort = false; 41 // 輸入文字檔名稱 42 String textFileName = null; 43 // 編碼方式 44 String encoding = "UTF-8"; 45 // 開始提取頁數 46 int startPage = 1; 47 // 結束提取頁數 48 int endPage = 3; 49 // 檔案輸入資料流,產生文字檔 50 Writer output = null; 51 // 記憶體中儲存的PDF Document 52 PDDocument document = null; 53 54 File outputFile = null; 55 try { 56 57 // 從本地裝載檔案 58 //注意參數已不是以前版本中的URL.而是File。 59 System.out.println("開始裝載檔案"+pdfFile.getName()); 60 document = PDDocument.load(pdfFile); 61 if (pdfFile.getName().length() > 4) { 62 textFileName = pdfFile.getName().substring(0, pdfFile.getName().length() - 4) + ".txt"; 63 outputFile = new File(pdfFile.getParent(),textFileName); 64 System.out.println("新檔案絕對路徑為:"+outputFile.getAbsolutePath()); 65 66 67 } 68 System.out.println("裝載檔案結束"); 69 70 71 System.out.println("開始寫到txt檔案中"); 72 // 檔案輸入資料流,寫入檔案倒textFile 73 output = new OutputStreamWriter(new FileOutputStream(outputFile),encoding); 74 System.out.println("寫入txt檔案結束"); 75 // PDFTextStripper來提取文本 76 PDFTextStripper stripper = null; 77 stripper = new PDFTextStripper(); 78 // 設定是否排序 79 stripper.setSortByPosition(sort); 80 // 設定起始頁 81 stripper.setStartPage(startPage); 82 // 設定結束頁 83 stripper.setEndPage(endPage); 84 // 調用PDFTextStripper的writeText提取並輸出文本 85 System.out.println("開始調用writeText方法"); 86 stripper.writeText(document, output); 87 System.out.println("調用writeText方法結束"); 88 }catch (Exception e) { 89 e.printStackTrace(); 90 }finally { 91 if (output != null) { 92 // 關閉輸出資料流 93 output.close(); 94 } 95 if (document != null) { 96 // 關閉PDF Document 97 document.close(); 98 } 99 }100 }101 }View Code
有很多打樁的語句,可以自行去除。
6.遇到的問題及解決方案
1)一開始使用的並不是PDF2.0版本,而是1.8版(2.0版本還是實驗版本,故選用了早期的1.8版本)。但使用1.8版本,使用PDDocument.load(String)方法時,老是出現這個異常——“java.io.IOException: Push back buffer is full”。
解決方案:上述問題困擾了筆者很久。筆者為此重新複習了IO和NIO的一些知識,並查閱了PDFBox英文API文檔(1.8版本),均無解決思路。後大量查閱資料得知,這可能是1.8版本出現的bug。2.0版本修複了bug。改為2.0版本,果然就好了。需要提醒的是,2.0版本PDDocument.load()方法參數為File類型,不再是String類型。可以參閱官方API文檔。
PDFBox的使用——分頁提取PDF文本