最近搞到一个任务是要解析一套雅思题目并提取其中的高频单词。那如何使用java来解析一个pdf文件呢?
首先我们要知道这需要springboot框架来进行创建,需要的PDFTextStripper
是一个用于PDF文档中提取文本的类,它是Apache PDFBox
的一个类用于处理PDF文档的开源的库。其主要功能是解析文档的内容流,所以我们需要定义一个流来提取其中的文字内容。
所以我们先引入pdfbox相关的依赖,具体如下:
<dependency><groupId>org.apache.pdfbox</groupId><artifactId>fontbox</artifactId><version>2.0.0</version>
</dependency>
<dependency><groupId>org.apache.pdfbox</groupId><artifactId>jempbox</artifactId><version>1.8.11</version>
</dependency>
<dependency><groupId>org.apache.pdfbox</groupId><artifactId>xmpbox</artifactId><version>2.0.0</version>
</dependency>
<dependency><groupId>org.apache.pdfbox</groupId><artifactId>preflight</artifactId><version>2.0.0</version>
</dependency>
<dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox-tools</artifactId><version>2.0.0</version>
</dependency>
这是比较完整的一套依赖。我们把提交pdf和接收pdf用一种post的方式进行上传,这样会显得提交方式非常的灵活。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Upload PDF</title>
</head>
<body>
<h1>Upload PDF File</h1>
<form action="/api/files/upload-pdf" method="post" enctype="multipart/form-data"><input type="file" name="file" accept="application/pdf" required><button type="submit">Upload</button>
</form>
</body>
</html>
然后我们简单写一个controller
@RestController
@RequestMapping("/api/files")
public class ReadFileController {@Autowiredprivate ExtractService extractService;@PostMapping("/upload-pdf")public ResponseEntity<Object> uploadPdf(@RequestParam("file") MultipartFile file) {// 验证文件是否为空if (file.isEmpty()) {return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("File is empty");}// 验证文件类型是否为PDFif (!"application/pdf".equals(file.getContentType())) {return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Only PDF files are allowed");}String file_name = file.getOriginalFilename();String filePath = extractService.Run(file,file_name);
我们可以看到表单提交的action就是我们controller里面的路径,提交之后我们在做一个简单的文件类型判断之后就返回给了业务层进行解析。
private StringBuilder accumulatedText = new StringBuilder();
public List<Map.Entry<String, Integer>> read_file(MultipartFile file) {try (InputStream inputStream = file.getInputStream()) {try (PDDocument doc = PDDocument.load(inputStream)) {PDFTextStripper textStripper = new PDFTextStripper();textStripper.setSortByPosition(true);String allText = textStripper.getText(doc);accumulatedText.append(allText).append("\n");}} catch (IOException e) {e.printStackTrace();}return getSortedWordList(accumulatedText.toString());}
这段代码首先通过file.getInputStream()
获取上传文件对应的输入流,这个过程就避免了我们先把文件存到磁盘,而是直接从文件中读数据。PDDocument
是Apache PDFBox
库中的一个类,用于表示PDF文档。此语句确保了PDDocument
对象在使用后会被正确关闭。PDFTextStripper
是 Apache PDFBox
库中的一个类,用于从 PDF 文档中提取文本。它提供了一种简单而有效的方法来遍历 PDF 的内容,并将其中的文本元素抽取出来形成字符串。PDFTextStripper
可以解析 PDF 页面上的文本对象,并将它们转换为可读的字符串格式。通过设置 setSortByPosition(true)
,可以确保提取的文本按照其在页面上的实际位置进行排序,这有助于保持文本的自然阅读顺序。默认情况下,PDFTextStripper
按照文本对象在 PDF 文件中的出现顺序提取文本,这可能会导致文本顺序混乱。
StringBuilder
是 Java 中的一个类,它提供了可变的字符序列,允许你高效地构建、修改和操作字符串。与 String 类不同,String 是不可变的(immutable)
,每次对 String 的修改都会创建一个新的 String 对象,而 StringBuilder
是可变的(mutable),可以在同一个对象上进行多次修改而不创建新的对象。这使得 StringBuilder
在需要频繁修改字符串的情况下更加高效。
尽管 PDFTextStripper 主要用于文本提取,但它也可以与 PDFStreamEngine 结合使用,以处理 PDF 中的其他内容,如图像或矢量图形。目前我还没有用到,日后需要解析非文字内容再做解析。