java 使用 POI 操作 XWPFDocumen 创建和读取 Office Word 文档基础篇
注:有不正确的地方还望大神能够指出,抱拳了 老铁!
参考 API:http://poi.apache.org/apidocs/org/apache/poi/xwpf/usermodel/XWPFDocument.html
主要参考文章 1:http://www.cnblogs.com/Springmoon-venn/p/5494602.html
主要参考文章 2:http://elim.iteye.com/blog/2049110
主要参考文章 3:http://doc.okbase.net/oh_Maxy/archive/154764.html
一、基本属性
建议大家使用 office word 来创建文档。(wps 和 word 结构有些不一样)
IBodyElement ------------------- 迭代器(段落和表格)
XWPFComment ------------------- 评论(个人理解应该是批注)
XWPFSDT
XWPFFooter ------------------- 页脚
XWPFFootnotes ------------------- 脚注
XWPFHeader ------------------- 页眉
XWPFHyperlink ------------------- 超链接
XWPFNumbering ------------------- 编号(我也不知是啥...)
XWPFParagraph ------------------- 段落
XWPFPictureData ------------------- 图片
XWPFStyles ------------------- 样式(设置多级标题的时候用)
XWPFTable ------------------- 表格
二、正文段落
一个文档包含多个段落,一个段落包含多个 Runs,一个 Runs 包含多个 Run,Run 是文档的最小单元
获取所有段落:List paragraphs = word.getParagraphs();
获取一个段落中的所有 Runs:List xwpfRuns = xwpfParagraph.getRuns();
获取一个 Runs 中的一个 Run:XWPFRun run = xwpfRuns.get(index);
XWPFRun-- 代表具有相同属性的一段文本
三、正文表格
一个文档包含多个表格,一个表格包含多行,一行包含多列(格),每一格的内容相当于一个完整的文档
获取所有表格:List xwpfTables = doc.getTables();
获取一个表格中的所有行:List xwpfTableRows = xwpfTable.getRows();
获取一行中的所有列:List xwpfTableCells = xwpfTableRow.getTableCells();
获取一格里的内容:List paragraphs = xwpfTableCell.getParagraphs();
之后和正文段落一样
注:
- 表格的一格相当于一个完整的 docx 文档,只是没有页眉和页脚。里面可以有表格,使用 xwpfTableCell.getTables() 获取,and so on
- 在 poi 文档中段落和表格是完全分开的,如果在两个段落中有一个表格,在 poi 中是没办法确定表格在段落中间的。(当然除非你本来知道了,这句是废话)。只有文档的格式固定,才能正确的得到文档的结构
个人理解:我不能确定表格所处的位置(第一个段落后面 ,还是第二个段落后面...)
3、页眉:
一个文档可以有多个页眉, 页眉里面可以包含段落和表格
获取文档的页眉:List headerList = doc.getHeaderList();
获取页眉里的所有段落:List paras = header.getParagraphs();
获取页眉里的所有表格:List tables = header.getTables();
之后就一样了
四、页脚:
页脚和页眉基本类似,可以获取表示页数的角标
言归正传 ------- 干货:
五、通过 XWPFDocument 读:段落 + 表格
a、获取文档的所有段落
InputStream is = new FileInputStream("D:\table.docx");
XWPFDocument doc = new XWPFDocument(is);
List paras = doc.getParagraphs();
获取段落内容
for (XWPFParagraph para : paras) {// 当前段落的属性 //CTPPr pr = para.getCTP().getPPr();
System.out.println(para.getText());
}
b、获取文档中所有的表格
List tables = doc.getTables();
List rows;
List 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());;
}
}
}
六、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 rows = table.getRows(); // 表格属性
CTTblPr tablePr = table.getCTTbl().addNewTblPr(); // 表格宽度
CTTblWidth width = tablePr.addNewTblW();
width.setW(BigInteger.valueOf(8000));
XWPFTableRow row;
List cells;
XWPFTableCell cell;
int rowSize = rows.size();
int cellSize;
for (int i=0; i) {
row = rows.get(i); // 新增单元格
row.addNewTableCell(); // 设置行的高度
row.setHeight(500); // 行属性 //CTTrPr rowPr = row.getCtRow().addNewTrPr(); // 这种方式是可以获取到新增的 cell 的。 //List list = row.getCtRow().getTcList();
cells = row.getTableCells();
cellSize = cells.size(); for (int j=0; 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 params) {
List runs;
Matcher matcher; if (this.matcher(para.getParagraphText()).find()) {
runs = para.getRuns(); for (int i=0; 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 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); }
创建文本对象
XWPFDocument docxDocument = new XWPFDocument();
创建段落对象
XWPFParagraph paragraphX = docxDocument.createParagraph();
XWPFParagraph 段落属性
//paragraphX.addRun(runX0);//似乎并没有什么卵用
//paragraphX.removeRun(1);//按数组下标删除run(文本)
paragraphX.setAlignment(ParagraphAlignment.LEFT);//对齐方式
//paragraphX.setBorderBetween(Borders.LIGHTNING_1);//边界 (但是我设置了好几个值都没有效果)
//paragraphX.setFirstLineIndent(100);//首行缩进:-----效果不详
//paragraphX.setFontAlignment(3);//字体对齐方式:1左对齐 2居中3右对齐
//paragraphX.setIndentationFirstLine(567);//首行缩进:567==1厘米
//paragraphX.setIndentationHanging(567);//指定缩进,从父段落的第一行删除,将第一行上的缩进移回到文本流方向的开头。
//paragraphX.setIndentationLeft(2);//-----效果不详
//paragraphX.setIndentationRight(2);//-----效果不详
//paragraphX.setIndentFromLeft(2);//-----效果不详
//paragraphX.setIndentFromRight(2);//-----效果不详
//paragraphX.setNumID(new BigInteger("3"));//设置段落编号-----有效果看不懂(仅仅是整段缩进4个字)
//paragraphX.setPageBreak(true);//段前分页
//paragraphX.setSpacingAfter(1);//指定文档中此段最后一行以绝对单位添加的间距。-----效果不详
//paragraphX.setSpacingBeforeLines(2);//指定在该行的第一行中添加行单位之前的间距-----效果不详
//paragraphX.setStyle("标题 3");//段落样式:需要结合addCustomHeadingStyle(docxDocument, "标题 3", 3)配合使用
paragraphX.setVerticalAlignment(TextAlignment.BOTTOM);//文本对齐方式(我猜在 table 里面会有比较明显得到效果)
paragraphX.setWordWrapped(true);//这个元素指定一个消费者是否应该突破拉丁语文本超过一行的文本范围,打破单词跨两行(打破字符水平)或移动到以下行字(打破字级)-----(我没看懂: 填个 false 还报异常了)
java 使用 POI 操作 XWPFDocumen 创建和读取 Office Word 文档基础篇的更多相关文章
- XWPFDocument创建和读取Office Word文档基础篇(一)
注:有不正确的地方还望大神能够指出,抱拳了 老铁! 参考API:http://poi.apache.org/apidocs/org/apache/poi/xwpf/usermodel/XWPFDo ...
- 使用ABAP编程实现对微软Office Word文档的操作
SAP ABAP里提供了一个标准的类CL_DOCX_DOCUMENT,提供了本地以".docx"结尾的微软Office word文档的读和写操作. 本文介绍了ABAP类CL_DOC ...
- 基于springboot的freemarker创建指定格式的word文档
在web或其他应用中,经常我们需要导出或者预览word文档,比较实际的例子有招聘网站上预览或者导出个人简历,使用POI导出excel会非常的方便,但是如果想导出word,由于其格式控制非常复杂,故而使 ...
- java通过freemarker导出包含富文本图片的word文档
废话不多说,进入正题! 本文重点在于:对富文本图片的导出(基础的freemarker+word模板导出这里不做详细解说哈) 参考文章:http://www.cnblogs.com/liaofeifig ...
- c#写word文档基础操作(自己控制样式)
下面一个函数,建立一个Word 文档,添加页眉.页脚,在内容中两个不同字体的Hello!!! 来自 <http://bbs.csdn.net/topics/340041961> pub ...
- Java操作word文档使用JACOB和POI操作word,Excel,PPT需要的jar包
可参考文档: http://wibiline.iteye.com/blog/1725492 下载jar包 http://download.csdn.net/download/javashixiaofe ...
- java 使用poi读取word文档存入数据库
使用的poi jar包需要自己下载 读取的word文档中含有多个图片,所以分为两个部分,一个部分读取各个表格中内容,一个是将所有图片截取出来: /** * 遍历段落内容 * docxReadPath ...
- 整理关于Java进行word文档的数据动态数据填充
首先我们看下,别人整理的关于Java生成doc 的 资料. java生成word的几种方案 1. Jacob是Java-COM Bridge的缩写,它在Java与微软的COM组件之间构建一座桥梁.使用 ...
- 使用Java生成word文档(附源码)
当我们使用Java生成word文档时,通常首先会想到iText和POI,这是因为我们习惯了使用这两种方法操作Excel,自然而然的也想使用这种生成word文档.但是当我们需要动态生成word时,通常不 ...
随机推荐
- Windows中使用CopyFile函数复制文件,出现string转LPCTSTR问题(附代码)
原因: 同一张图片,用imread读取,imwrite重新写入另外一个文件夹,然后再次读取发现前后异常,这是因为读取后转成Mat格式,然后写入转成图片格式,这个过程会对图片产生损失. 因此后来采用直接 ...
- BZOJ 1822[JSOI2010]Frozen Nova 冷冻波
网络流+二分. n^3枚举判断每个巫妖可以攻击的精灵,向其连1的边,每个精灵向汇点连1的边. 二分答案,修改源点流向每个巫妖的cap,跑最大流看是否等于精灵数. 恩,看起来没什么毛病. 然后狂WA不止 ...
- SQL语句中GROUP BY的问题
今天查询数据库时用到集合函数sum(drp),遇到问题: 百度后,确定如下问题:当select后面查询字段有sum(drp)以外的字段时,必须使用group by函数,对数据进行排序,且查询字段中除s ...
- WPF DataGrid 数据绑定之"List配合Dictionary"
WPF 的DataGrid是WPF中最为强大的控件之一,可以通过各种方式绑定 例如通过最为形似的dataTable来绑定 本文则用List<Dictionary<K,V>>来绑 ...
- 自定义切面实现用户日志记录--AOP
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的 ...
- python 可迭代对象,迭代器,生成器的区别及使用
可迭代对象 可迭代对象类型:list,dict,tuple,str,set,deque等 如何判断一个对象是否是可迭代对象,可以通过dir()方法看它里面有没有__iter__方法,如果有这个方法就是 ...
- HNOI 2019 多边形
HNOI 2019 多边形 题意 小 R 与小 W 在玩游戏. 他们有一个边数为\(n\)的凸多边形,其顶点沿逆时针方向标号依次为\(1,2,3...n\).最开始凸多边形中有\(n\)条线段,即多边 ...
- C++ 静态绑定与动态绑定------绝不重新定义继承而来的缺省参数
在了解静态绑定和动态绑定之前,先了解什么是对象的静态类型,什么是对象的动态类型. 对象的静态类型:对象在声明时采用的类型.是在编译器决定的. 对象的动态类型:目前所指对象的类型.是在运行期决定的. 动 ...
- JAVA面试常见问题之数据库篇
1.MySQL 索引使用的注意事项 更新频繁的列不要加索引 数据量小的表不要加索引 重复数据多的字段不要加索引,比如性别字段 首先应该考虑对where 和 order by 涉及的列上建立索引 2.D ...
- Linux学习(一):软链接和硬链接
今天起,决定开始自学Linux命令及Shell脚本,并用Linux学习(命令行,Shell及其他知识点)这一系列记录下自己的心路历程,内容不分先后,只记录自己觉得有必要的,简单的就不记了! 第一个知识 ...