zoukankan      html  css  js  c++  java
  • XWPFDocument创建和读取Office Word文档基础篇(一)

    注:有不正确的地方还望大神能够指出,抱拳了 老铁!
     
     
     
    建议大家使用office word来创建文档。(wps和word结构有些不一样)
     
    IBodyElement -------------------迭代器(段落和表格)
    XWPFComment -------------------评论(个人理解应该是批注)
    XWPFSDT
    XWPFFooter -------------------页脚
    XWPFFootnotes -------------------脚注
    XWPFHeader -------------------页眉
    XWPFHyperlink -------------------超链接
    XWPFNumbering -------------------编号(我也不知是啥...)
    XWPFParagraph -------------------段落
    XWPFPictureData -------------------图片
    XWPFStyles -------------------样式(设置多级标题的时候用)
    XWPFTable -------------------表格
     
    1、正文段落
    一个文档包含多个段落,一个段落包含多个Runs,一个Runs包含多个Run,Run是文档的最小单元
    获取所有段落:List<XWPFParagraph> paragraphs = word.getParagraphs();
    获取一个段落中的所有Runs:List<XWPFRun> xwpfRuns = xwpfParagraph.getRuns();
    获取一个Runs中的一个Run:XWPFRun run = xwpfRuns.get(index);
     
    XWPFRun--代表具有相同属性的一段文本
     
     
    2、正文表格
    一个文档包含多个表格,一个表格包含多行,一行包含多列(格),每一格的内容相当于一个完整的文档
    获取所有表格:List<XWPFTable> xwpfTables = doc.getTables();
    获取一个表格中的所有行:List<XWPFTableRow> xwpfTableRows = xwpfTable.getRows();
    获取一行中的所有列:List<XWPFTableCell> xwpfTableCells = xwpfTableRow.getTableCells();
    获取一格里的内容:List<XWPFParagraph> paragraphs = xwpfTableCell.getParagraphs();
    之后和正文段落一样
     
     
    注:
    1. 表格的一格相当于一个完整的docx文档,只是没有页眉和页脚。里面可以有表格,使用xwpfTableCell.getTables()获取,and so on
    2. 在poi文档中段落和表格是完全分开的,如果在两个段落中有一个表格,在poi中是没办法确定表格在段落中间的。(当然除非你本来知道了,这句是废话)。只有文档的格式固定,才能正确的得到文档的结构
     
    个人理解:我不能确定表格所处的位置(第一个段落后面 ,还是第二个段落后面...)
     
     
    3、页眉:
    一个文档可以有多个页眉,页眉里面可以包含段落和表格
    获取文档的页眉:List<XWPFHeader> headerList = doc.getHeaderList();
    获取页眉里的所有段落:List<XWPFParagraph> paras = header.getParagraphs();
    获取页眉里的所有表格:List<XWPFTable> tables = header.getTables();
    之后就一样了
    4、页脚:
    页脚和页眉基本类似,可以获取表示页数的角标
     
     
     
    言归正传-------干货:
    1、通过XWPFDocument读:段落+表格
     
    a、获取文档的所有段落
    InputStream is = new FileInputStream("D:\table.docx");  
    XWPFDocument doc = new XWPFDocument(is);  
    List<XWPFParagraph> paras = doc.getParagraphs(); 
    获取段落内容
    for (XWPFParagraph para : paras) {  
        //当前段落的属性  
    //CTPPr pr = para.getCTP().getPPr();  
    System.out.println(para.getText());  
    } 
     
     
    b、获取文档中所有的表格  
     
    List<XWPFTable> tables = doc.getTables();  
    List<XWPFTableRow> rows;  
    List<XWPFTableCell> cells;  
    
    for (XWPFTable table : tables) {  
        //表格属性  
        CTTblPr pr = table.getCTTbl().getTblPr();  
        //获取表格对应的行  
        rows = table.getRows();  
        for (XWPFTableRow row : rows) {  
            //获取行对应的单元格  
            cells = row.getTableCells();  
            for (XWPFTableCell cell : cells) {  
                System.out.println(cell.getText());;  
            }  
        }  
    }
     
    2、XWPFDocument生成word
     
    直接new一个空的XWPFDocument,之后再往这个XWPFDocument里面填充内容,然后再把它写入到对应的输出流中。
     
    新建一个文档
    XWPFDocument doc = new XWPFDocument();
    //创建一个段落
    XWPFParagraph para = doc.createParagraph();
     
    //一个XWPFRun代表具有相同属性的一个区域:一段文本
    XWPFRun run = para.createRun();
    run.setBold(true); //加粗
    run.setText("加粗的内容");
    run = para.createRun();
    run.setColor("FF0000");
    run.setText("红色的字。");
    OutputStream os = new FileOutputStream("D:\simpleWrite.docx");
    //把doc输出到输出流
    doc.write(os);
    this.close(os);
     
     
    新建一个表格
    //XWPFDocument doc = new XWPFDocument();  
    //创建一个5行5列的表格  
    XWPFTable table = doc.createTable(5, 5);  
    //这里增加的列原本初始化创建的那5行在通过getTableCells()方法获取时获取不到,但通过row新增的就可以。  
    //table.addNewCol(); //给表格增加一列,变成6列  
    table.createRow(); //给表格新增一行,变成6行  
    List<XWPFTableRow> rows = table.getRows();  
    //表格属性  
    CTTblPr tablePr = table.getCTTbl().addNewTblPr();  
    //表格宽度  
    CTTblWidth width = tablePr.addNewTblW();  
    width.setW(BigInteger.valueOf(8000));  
    XWPFTableRow row;  
    List<XWPFTableCell> cells;  
    XWPFTableCell cell;  
    int rowSize = rows.size();  
    int cellSize;  
    for (int i=0; i<rowSize; i++) {  
     row = rows.get(i);  
     //新增单元格  
     row.addNewTableCell();  
     //设置行的高度  
     row.setHeight(500);  
     //行属性  
    //CTTrPr rowPr = row.getCtRow().addNewTrPr();  
     //这种方式是可以获取到新增的cell的。  
    //List<CTTc> list = row.getCtRow().getTcList();  
     cells = row.getTableCells();  
     cellSize = cells.size();  
     for (int j=0; j<cellSize; j++) {  
        cell = cells.get(j);  
        if ((i+j)%2==0) {  
            //设置单元格的颜色  
            cell.setColor("ff0000"); //红色  
        } else {  
            cell.setColor("0000ff"); //蓝色  
        }  
        //单元格属性  
        CTTcPr cellPr = cell.getCTTc().addNewTcPr();  
        cellPr.addNewVAlign().setVal(STVerticalJc.CENTER);  
        if (j == 3) {  
            //设置宽度  
            cellPr.addNewTcW().setW(BigInteger.valueOf(3000));  
        }  
        cell.setText(i + ", " + j);  
     }
    }  
    //文件不存在时会自动创建  
    OutputStream os = new FileOutputStream("D:\table.docx");  
    //写入文件  
    doc.write(os);  
    this.close(os); 
     
     
    段落内容替换
    /** 
    * 替换段落里面的变量 
    * @param para 要替换的段落 
    * @param params 参数 
    */  
    private void replaceInPara(XWPFParagraph para, Map<String, Object> params) {  
      List<XWPFRun> runs;  
      Matcher matcher;  
      if (this.matcher(para.getParagraphText()).find()) {  
         runs = para.getRuns();  
         for (int i=0; i<runs.size(); i++) {  
            XWPFRun run = runs.get(i);  
            String runText = run.toString();  
            matcher = this.matcher(runText);  
            if (matcher.find()) {  
                while ((matcher = this.matcher(runText)).find()) {  
                   runText = matcher.replaceFirst(String.valueOf(params.get(matcher.group(1))));  
                }  
                //直接调用XWPFRun的setText()方法设置文本时,在底层会重新创建一个XWPFRun,把文本附加在当前文本后面,  
                //所以我们不能直接设值,需要先删除当前run,然后再自己手动插入一个新的run。  
                para.removeRun(i);  
                para.insertNewRun(i).setText(runText);  
            }  
         }  
      }  
    }   
     
    直接调用XWPFRun的setText()方法设置文本时,在底层会重新创建一个XWPFRun,把文本附加在当前文本后面,所以我们不能直接设值,需要先删除当前run,然后再自己手动插入一个新的run。
     
     
    //抽取 word docx文件中的图片
    String path ="D://abc.docx";  
    File file = new File(path);  
    try {  
      FileInputStream fis = new FileInputStream(file);  
      XWPFDocument document = new XWPFDocument(fis);  
      XWPFWordExtractor xwpfWordExtractor = new XWPFWordExtractor(document);  
      String text = xwpfWordExtractor.getText();  
      System.out.println(text);  
      List<XWPFPictureData> picList = document.getAllPictures();  
      for (XWPFPictureData pic : picList) {  
        System.out.println(pic.getPictureType() + file.separator + pic.suggestFileExtension()  
            +file.separator+pic.getFileName());  
        byte[] bytev = pic.getData();  
        FileOutputStream fos = new FileOutputStream("D:\abc\docxImage\"+pic.getFileName());   
        fos.write(bytev);  
      }  
      fis.close();  
    } catch (IOException e) {  
      e.printStackTrace();  
    }  
    }  
     
     
    多级标题结构
    /**
     * 自定义样式方式写word,参考statckoverflow的源码
     * 
     * @throws IOException
     */
    public static void writeSimpleDocxFile() throws IOException {
        XWPFDocument docxDocument = new XWPFDocument();
    
        // 老外自定义了一个名字,中文版的最好还是按照word给的标题名来,否则级别上可能会乱
        addCustomHeadingStyle(docxDocument, "标题 1", 1);
        addCustomHeadingStyle(docxDocument, "标题 2", 2);
    
        // 标题1
        XWPFParagraph paragraph = docxDocument.createParagraph();
        XWPFRun run = paragraph.createRun();
        run.setText("标题 1");
        paragraph.setStyle("标题 1");
    
        // 标题2
        XWPFParagraph paragraph2 = docxDocument.createParagraph();
        XWPFRun run2 = paragraph2.createRun();
        run2.setText("标题 2");
        paragraph2.setStyle("标题 2");
    
        // 正文
        XWPFParagraph paragraphX = docxDocument.createParagraph();
        XWPFRun runX = paragraphX.createRun();
        runX.setText("正文");
    // word写入到文件 FileOutputStream fos = new FileOutputStream("D:/myDoc2.docx"); docxDocument.write(fos); fos.close(); } /** * 增加自定义标题样式。这里用的是stackoverflow的源码 * * @param docxDocument 目标文档 * @param strStyleId 样式名称 * @param headingLevel 样式级别 */ private static void addCustomHeadingStyle(XWPFDocument docxDocument, String strStyleId, int headingLevel) { CTStyle ctStyle = CTStyle.Factory.newInstance(); ctStyle.setStyleId(strStyleId); CTString styleName = CTString.Factory.newInstance(); styleName.setVal(strStyleId); ctStyle.setName(styleName); CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance(); indentNumber.setVal(BigInteger.valueOf(headingLevel)); // lower number > style is more prominent in the formats bar ctStyle.setUiPriority(indentNumber); CTOnOff onoffnull = CTOnOff.Factory.newInstance(); ctStyle.setUnhideWhenUsed(onoffnull); // style shows up in the formats bar ctStyle.setQFormat(onoffnull); // style defines a heading of the given level CTPPr ppr = CTPPr.Factory.newInstance(); ppr.setOutlineLvl(indentNumber); ctStyle.setPPr(ppr); XWPFStyle style = new XWPFStyle(ctStyle); // is a null op if already defined XWPFStyles styles = docxDocument.createStyles(); style.setType(STStyleType.PARAGRAPH); styles.addStyle(style); }
  • 相关阅读:
    java stackoverflowerror与outofmemoryerror区别
    JVM参数笔记
    记录一次JVM配置优化的案例
    JVM相关内容简介(转)
    Spring boot中的定时任务(计划任务)
    netty学习:UDP服务器与Spring整合(2)
    netty学习:UDP服务器与Spring整合
    maven 纯注解一步一步搭建Spring Mvc项目(入门)
    将class类对象转化成json的数据格式
    Spring五个事务隔离级别和七个事务传播行为
  • 原文地址:https://www.cnblogs.com/unruly/p/7479518.html
Copyright © 2011-2022 走看看