前言
在日常工作中,word、excel、pdf等是我们最常见、最常用的文件格式,那么,随之而来的问题是:如何有效地对这3种文件进行相互转换?相信大家多多少少都有遇到过这样的转换需求。其中,word与excel的相互转换以及word、excel转为pdf是比较简单,比较麻烦的是pdf转excel。由于工作需要,作者恰好遇到了pdf转excel的需求,在此分享一下个人经验,与大家相互学习。
思路
文件格式转换的思路很简单,就是将源文件内容读取出来、然后输出保存为目标格式。下面我们用三种方式将pdf转换为excel。
java实现——spire.pdf
步骤一:引入依赖
<repositories>
<repository>
<id>com.e-iceblue</id>
<url>http://repo.e-iceblue.cn/repository/maven-public/</url>
</repository>
</repositories>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.pdf</artifactId>
<version>5.1.0</version>
</dependency>
ps:如果maven方式无法下载依赖,可以直接访问 Repository - Nexus Repository Manager官方仓库,将对应jar包下载下来、再通过maven安装到本地仓或直接copy到项目中添加为依赖即可。
步骤二:代码示例
public static void main(String[] args) {
// 加载pdf文件
PdfDocument pdf = new PdfDocument();
pdf.loadFromFile("源.pdf");
//保存为Excel文档
pdf.saveToFile("目标.xlsx", FileFormat.XLSX);
pdf.dispose();
}
优点:
- 简单、代码量少
- 纯代码实现,方便集成到项目
- 所见即所得——excel里的表格与pdf里的看上去是一样的
缺点:
- 封装的很好但是不够灵活
- 页码、空白部分也会被输出到excel,产生多余的行列
python实现——pdfplumber+xlwt
步骤一:环境准备
- 安装python环境
- pip install安装pdfplumber、xlwt库
- 项目中引入安装的库
步骤二:代码示例
from os import pread
import pdfplumber
import xlwt
# 读取源pdf文件
pdf = pdfplumber.open("./test.pdf")
# 创建excel
workboot = xlwt.Workbook()
# 创建sheet
sheet = workboot.add_sheet("Sheet1")
# 行计数
i = 0
# 循环读取pdf的每一页
for page in pdf.pages:
# 读取表格
for table in page.extract_tables():
# 读取表格中的行
for row in table:
print(row)
for j in range(len(row)):
sheet.write(i,j,row[j])
i+=1
pdf.close()
print(i)
workboot.save("./test.xlsx")
优点:
- 代码量少,简单
- 灵活,可以操作pdf中表格的每一个单元格
- 纯代码实现,方便集成到项目
缺点:
- 会忽略掉所有表格样式,相当于只粘贴文本
java配合wps软件实现——pdfbox、poi(wps vip用户请忽略以下内容^_^)
专业的事情找专业的软件做肯定是比较完美的,wps作为免费办公软件还是想当好用的。但是,pdf转excel作为高级功能在wps里是需要开通vip会员才能使用的!不过,5页及以下pdf文件的转换对普通用户也是免费的。于是我们可以这么操作:先用代码拆分pdf、每5页保存一个文件,再使用wps将拆分后的文件分别转换;最后使用代码将转换后的excel合并为一个文件。
步骤一:引入依赖
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.24</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.0.0</version>
</dependency>
步骤二:拆分pdf
/**
* 拆分pdf
* @param root
* @throws Exception
*/
public static void splitPdf(String root) throws Exception{
File file = new File(root);
PDDocument pdDocument = PDDocument.load(file);
// 拆分后的文件集合保存目录
String saveTo = root.substring(0,root.lastIndexOf("."));
File save = new File(saveTo);
if (!save.exists()){
save.mkdirs();
}
PDPageTree pages = pdDocument.getPages();
int count = pages.getCount();
System.out.println(count);
int i = 1;
List<PDPage> list = new ArrayList<>();
for (PDPage page : pages) {
list.add(page);
if (i % 5 == 0){
PDDocument split = new PDDocument();
for (int j = 0; j < 5; j++) {
split.addPage(list.remove(0));
}
// 每5页作为新的pdf输出,以数字序号命名
split.save(new File( saveTo + "\\" + (i/5) + ".pdf"));
}
i++;
}
// 不满5页的尾数处理
if (list.size() > 0){
PDDocument split = new PDDocument();
for (PDPage pdPage : list) {
split.addPage(pdPage);
}
split.save(new File(saveTo + "\\" + (count/5 + 1) + ".pdf") );
}
}
步骤三:合并excel
/**
* 合并excel
* @param root
* @throws Exception
*/
public static void mergeExcel(String root) throws Exception{
Workbook workbook = WorkbookFactory.create(true);
Sheet sheet = workbook.createSheet("sheet1");
// excel文件集合
long count = Files.list(Paths.get(root)).filter(path -> path.toString().endsWith(".xlsx")).count();
System.out.println("总数:" + count);
int rowNumber = 0;
// excel文件以数字序列命名的
for (long l = 1; l <= count; l++) {
String fileName = root + l + ".xlsx";
System.out.println("处理:" + fileName);
Workbook temp = WorkbookFactory.create(new File(fileName));
Sheet tempSheet = temp.getSheetAt(0);
for (Row cells : tempSheet) {
Row newRow = sheet.createRow(rowNumber++);
// 复制行格式
newRow.setHeight(cells.getHeight());
newRow.setHeightInPoints(cells.getHeightInPoints());
newRow.setRowStyle(cells.getRowStyle());
newRow.setZeroHeight(cells.getZeroHeight());
int cellNumber = 0;
for (Cell cell : cells) {
// 复制列格式
sheet.setColumnWidth(cellNumber,tempSheet.getColumnWidth(cellNumber));
// 复制数据
Cell newCell = newRow.createCell(cellNumber);
CellType cellType = CellType.valueOf(cell.getCellType().name());
switch (cellType){
case STRING:
newCell.setCellValue(cell.getStringCellValue());
break;
case BLANK:
newCell.setBlank();
break;
case NUMERIC:
newCell.setCellValue(cell.getNumericCellValue());
break;
default:
}
// 复制单元格格式
newCell.setCellComment(cell.getCellComment());
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.cloneStyleFrom(cell.getCellStyle());
newCell.setCellStyle(cellStyle);
newCell.setHyperlink(cell.getHyperlink());
cellNumber++;
}
}
// 合并单元格设置,合并区域的坐标需要根据上个文件的行数调整
int lastRowNum = sheet.getLastRowNum() - tempSheet.getLastRowNum();
for (CellRangeAddress mergedRegion : tempSheet.getMergedRegions()) {
int firstRow = mergedRegion.getFirstRow();
int lastRow = mergedRegion.getLastRow();
mergedRegion.setFirstRow(firstRow + lastRowNum);
mergedRegion.setLastRow(lastRow + lastRowNum);
sheet.addMergedRegion(mergedRegion);
}
temp.close();
}
workbook.write(new FileOutputStream(root + "合并.xlsx"));
workbook.close();
}
优点:
- 免费使用专业软件的付费功能
- pdf里的表格样式可以完美复制
缺点:
- 非纯代码实现,不能集成到项目
- 实现比较复杂,代码量多
总结
以上方式仅适用于pdf里的表格为非图片形式,如果表格以图片形式存在于pdf里是无法转换的。可能需要使用图文识别方面的技术,有了解的小伙伴可以留言哈。(wps是支持图片形式的表格识别的,不过作者没有亲测,vip可用)