Apache POI详解及Word文档读取示例

2022-03-30 10:07:50 浏览数 (1)

系列文章:

Java 操作 Office:POI 之 word 生成

Java 操作 Office:POI 之 word 图片处理

Java 操作 Office:POI word 之网络图片处理

Java 操作 Office:POI word 之表格格式

一 POI简介

Apache POI - the Java API for Microsoft Documents。根据官网描述,poi是微软文档系列的Java API。这里的微软文档(Microsoft Documents),就是指word、excel(xls 和 xlsx)、PowerPoint 等。poi官网地址:https://poi.apache.org/。目前最新版本为 22年1月14日发布的POI5.2.0。发布记录可参见:RELEASE-NOTES;change log:changes;下载列表:https://archive.apache.org/dist/poi/release/bin/

二 POI组成

2.1 4.1.0与5.2.0版本组成

我们下载了4.1.0 和 5.2.0 两个版本的bin包,并解压后进行对比:

auxiliary,lib,ooxml-lib几个目录相同,内部依赖暂时不做对比。下面的jar包是我们开发时需要引入的依赖。poi-${version}.jar, poi-examples-${version}.jar, poi-excelant-${version}.jar, poi-ooxml-${version}.jar, poi-scratchpad-${version}.jar,这几个是相同的。不同的地方是,4.1.0中的 poi-ooxml-schemas-${version}.jar,在5.2.0中变成了poi-ooxml-full-${version}.jar和poi-ooxml-lite-${version}.jar。

2.2 各jar包作用

在官网的components中有描述:Apache POI - Component Overview,这更详细的解释大家可以直接看原文内容:https://poi.apache.org/components/index.html。

下图是操作的文档类型与jar包之间的关系,通过这张表,可以明确当我们仅需要操作word或excel,以及2003或2007版本时,分别需要引入哪几个jar包(或maven依赖):

poi包内各jar包之间的依赖关系:

举个栗子:

只要操作excel,且是xls格式时,只需导入poi-version-yyyymmdd.jar。当我们还要使用xlsx格式、还要导入poi-ooxml-version-yyyymmdd.jar。至于poi-ooxml-schemas-version-yyyymmdd.jar这个jar基本不太会用到的。当我们需要操作word、ppt、viso、outlook等时需要用到poi-scratchpad-version-yyyymmdd.jar。

三 读取word内容

在本文开始挂的系列文章链接中,已经包含了word文档创建、生成表格等相关操作,接下来我们要尝试读取word文档内容,最好包含格式,这样可以配合前端实现word在线编辑的效果,方便在web系统中集成;也可以考虑通过这种方式配合自然语言处理的相关模型/服务,实现word文档关键内容提取。

如大家所熟知,word目前也有.doc 和 .docx两种格式,对这两种格式的读取方式也稍有不同。接下来我们通过代码来详细阐述。

3.1 poi版本和依赖引入

我们使用的是4.1.0版本的poi,引入的依赖如下:

代码语言:javascript复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>test</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>project</artifactId>
    <properties>
        <java.version>1.8</java.version>
        <poi.version>4.1.0</poi.version>
    </properties>

    <dependencies>

        <!-- office 相关依赖jar包 -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>${poi.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>${poi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>${poi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>${poi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>${poi.version}</version>
        </dependency>
    </dependencies>
</project>
代码语言:javascript复制

3.2 docx文件内容读取

通过XWPFWordExtractor读取文档内容:

代码语言:javascript复制
import org.apache.poi.ooxml.POIXMLProperties;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;

public class ReadWordContent {

    public static void main(String[] args) throws Exception {
        String wordPath = "你的word文档地址.docx";
        ReadWordContent readWordContent = new ReadWordContent();
        readWordContent.readByExtractor(wordPath);
    }

    /**
     * 通过XWPFWordExtractor访问XWPFDocument的内容
     * @throws Exception
     */
    public void readByExtractor(String path) throws Exception {
        InputStream is = new FileInputStream(path);
        XWPFDocument doc = new XWPFDocument(is);
        XWPFWordExtractor extractor = new XWPFWordExtractor(doc);
        String text = extractor.getText();
        System.out.println(text);
        /**
         * 打印文档信息
         */
        POIXMLProperties.CoreProperties coreProps = extractor.getCoreProperties();
        this.printCoreProperties(coreProps);
        this.close(is);
    }

    /**
     * 输出CoreProperties信息
     * @param coreProps
     */
    private void printCoreProperties(POIXMLProperties.CoreProperties coreProps) {
        String category = coreProps.getCategory(); //分类
        String creator = coreProps.getCreator(); //创建者,Microsoft Office User
        Date createdDate = coreProps.getCreated(); //创建时间
        String title = coreProps.getTitle(); //标题
        String description = coreProps.getDescription(); //描述,默认为null

        System.out.println(category);
        System.out.println(creator);
        System.out.println(createdDate);
        System.out.println(title);
        System.out.println(description);
    }

    /**
     * 关闭输入流
     * @param is
     */
    private void close(InputStream is) {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
代码语言:javascript复制

3.3 doc文档内容及格式读取

代码语言:javascript复制
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.model.StyleDescription;
import org.apache.poi.hwpf.model.StyleSheet;
import org.apache.poi.hwpf.usermodel.Paragraph;
import org.apache.poi.hwpf.usermodel.Range;

import java.io.*;

/**
 * 注:HWPFDocument对应 word的.doc,不支持.docx
 */
public class ReadWordWithFormat {

    public static void main(String[] args) throws Exception {
        String filePath = "你的word文档地址.doc";
        printWord(filePath);
    }

    public static void printWord(String filePath) throws IOException {
        InputStream is = new FileInputStream(filePath);
        HWPFDocument doc = new HWPFDocument(is);
        Range r = doc.getRange();// 文档范围
        // System.out.println("段落数:" r.numParagraphs());

        for (int i = 0; i < r.numParagraphs(); i  ) {
            Paragraph p = r.getParagraph(i);// 获取段落
            int numStyles = doc.getStyleSheet().numStyles();
            int styleIndex = p.getStyleIndex();

            StyleSheet style_sheet = doc.getStyleSheet();
            StyleDescription style = style_sheet.getStyleDescription(styleIndex);
            String styleName = style.getName();
            // 打印各段落的格式
            System.out.println(i "," styleIndex "," styleName);

//            String styleLoving = "标题";
//            if (!StringUtils.isEmpty(styleName) && styleName.startsWith(styleLoving)){
//                String text = p.text();// 段落文本
//                System.out.println(text);
//            }
        }

        doc.close();
    }

}
代码语言:javascript复制

在printWord()方法中,我们打印了文档的每个段落以及该段落的格式,以本地测试时使用的文档为例,输出如下:

代码语言:javascript复制
0,0,正文
1,0,正文
2,1,标题 1
3,2,标题 2
4,0,正文
5,2,标题 2
6,0,正文
7,2,标题 2
8,0,正文
9,0,正文
10,0,正文
11,2,标题 2
12,0,正文
13,1,标题 1
14,2,标题 2
15,0,正文
16,0,正文
17,2,标题 2
18,0,正文
19,1,标题 1

0 人点赞