Java实现PDF表格转CSV:仅获取列名无数据的问题求助
问题:PDF表格转CSV仅获取到列名,无法读取数据内容
我需要将PDF表格文件转换为CSV文件,已编写如下Java代码,但运行后仅能获取到5个列名,无法获取对应的数据。代码如下:
public static ArrayList<String[]> readParaFromPDF(String pdfPath, int pageNoStart, int pageNoEnd, int noOfColumnsInTable) { ArrayList<String[]> objArrayList = new ArrayList<>(); try { PDDocument document = PDDocument.load(new File(pdfPath)); document.getClass(); if (!document.isEncrypted()) { PDFTextStripperByArea stripper = new PDFTextStripperByArea(); stripper.setSortByPosition(true); PDFTextStripper tStripper = new PDFTextStripper(); tStripper.setStartPage(pageNoStart); tStripper.setEndPage(pageNoEnd); String pdfFileInText = tStripper.getText(document); // split by whitespace String Documentlines[] = pdfFileInText.split("\\r?\\n"); for (String line : Documentlines) { String lineArr[] = line.split("\\s+"); if (lineArr.length == noOfColumnsInTable) { for (String linedata : lineArr) { System.out.print(linedata + " "); } System.out.println(""); objArrayList.add(lineArr); } } } } catch (Exception e) { System.out.println("Exception " + e); } return objArrayList; }
解决方案
我看了你的代码,发现几个关键问题导致你只能拿到列名,读不到表格数据:
浪费了
PDFTextStripperByArea的能力:你初始化了这个专门用来精准提取指定区域文本的工具(非常适合表格场景),但完全没用到它,反而用普通的PDFTextStripper把整个页面文本扒下来再按空格分割。这种方式在表格单元格包含空格时会直接拆碎内容,而且PDF里的文本换行、空格不一定和视觉上的表格行、单元格对齐,导致分割后的数组长度和列数不匹配,被你的if (lineArr.length == noOfColumnsInTable)过滤掉了。简单分割逻辑太脆弱:PDF的文本提取结果和视觉排版不一定完全对应,尤其是复杂表格,靠换行和空格分割根本没法准确识别表格结构。
针对这些问题,给你两种可行的解决思路:
思路一:正确使用PDFTextStripperByArea提取表格
这个方法需要你先确定表格每一列在PDF页面上的坐标范围(可以用PDFBox自带的PDFDebugger工具查看坐标),然后给每个列定义专属区域,精准提取内容。
修改后的代码示例:
public static ArrayList<String[]> readParaFromPDF(String pdfPath, int pageNoStart, int pageNoEnd, int noOfColumnsInTable) { ArrayList<String[]> objArrayList = new ArrayList<>(); // 用try-with-resources自动关闭文档,避免资源泄漏 try (PDDocument document = PDDocument.load(new File(pdfPath))) { if (!document.isEncrypted()) { PDFTextStripperByArea stripper = new PDFTextStripperByArea(); stripper.setSortByPosition(true); // 这里需要根据你的PDF表格实际坐标调整! // 示例假设5列的x坐标范围分别是[0,100], [100,200], [200,300], [300,400], [400,500] // 用PDFDebugger打开PDF,就能看到表格列的具体坐标 stripper.addRegion("col1", new Rectangle2D.Double(0, 0, 100, 792)); stripper.addRegion("col2", new Rectangle2D.Double(100, 0, 100, 792)); stripper.addRegion("col3", new Rectangle2D.Double(200, 0, 100, 792)); stripper.addRegion("col4", new Rectangle2D.Double(300, 0, 100, 792)); stripper.addRegion("col5", new Rectangle2D.Double(400, 0, 100, 792)); // 遍历指定页码范围的页面 for (int pageNum = pageNoStart; pageNum <= pageNoEnd; pageNum++) { PDPage page = document.getPage(pageNum - 1); // PDFBox页码从0开始 stripper.extractRegions(page); // 提取每一列的文本并按行分割 String[] col1Lines = stripper.getTextForRegion("col1").split("\\r?\\n"); String[] col2Lines = stripper.getTextForRegion("col2").split("\\r?\\n"); String[] col3Lines = stripper.getTextForRegion("col3").split("\\r?\\n"); String[] col4Lines = stripper.getTextForRegion("col4").split("\\r?\\n"); String[] col5Lines = stripper.getTextForRegion("col5").split("\\r?\\n"); // 按行组合成表格数据 int maxRows = Math.max(Math.max(col1Lines.length, col2Lines.length), Math.max(col3Lines.length, Math.max(col4Lines.length, col5Lines.length))); for (int i = 0; i < maxRows; i++) { String[] row = new String[noOfColumnsInTable]; row[0] = i < col1Lines.length ? col1Lines[i].trim() : ""; row[1] = i < col2Lines.length ? col2Lines[i].trim() : ""; row[2] = i < col3Lines.length ? col3Lines[i].trim() : ""; row[3] = i < col4Lines.length ? col4Lines[i].trim() : ""; row[4] = i < col5Lines.length ? col5Lines[i].trim() : ""; objArrayList.add(row); } } } } catch (Exception e) { System.err.println("处理PDF时出错: " + e.getMessage()); e.printStackTrace(); } return objArrayList; }
思路二:使用专门的PDF表格提取库
如果你的表格结构复杂(比如有合并单元格、不规则列宽),手动定义坐标太麻烦,推荐用专门的表格提取库,比如Tabula-java或者PDFBox 2.0+自带的表格提取能力。
以Tabula-java为例,它能自动识别表格结构,代码更简洁:
// 需先在项目中引入Tabula-java的依赖(Maven/Gradle均可) public static ArrayList<String[]> readTableFromPDF(String pdfPath, int pageNoStart, int pageNoEnd) { ArrayList<String[]> objArrayList = new ArrayList<>(); try { TableExtractor extractor = new TableExtractor(pdfPath); extractor.setStartPage(pageNoStart); extractor.setEndPage(pageNoEnd); // 提取所有表格 List<Table> tables = extractor.extractTables(); for (Table table : tables) { // 遍历表格行,转换为数组 for (List<Cell> rowCells : table.getRows()) { String[] row = new String[rowCells.size()]; for (int i = 0; i < rowCells.size(); i++) { row[i] = rowCells.get(i).getText().trim(); } objArrayList.add(row); } } } catch (Exception e) { System.err.println("提取表格出错: " + e.getMessage()); e.printStackTrace(); } return objArrayList; }
调试小技巧:
- 用
PDFTextStripperByArea时,先打印每个区域的提取结果,确认坐标是否正确。 - 不管用哪种方法,先打印中间结果,看看文本提取是否符合预期,再调整逻辑。
内容的提问来源于stack exchange,提问作者user9282535
相关产品推荐
相关产品推荐

