基于java合并.doc和docx格式的Word⽂件
注:摘录⾃
之前⽤过jacob 合并.doc,但是是有jacob有弊端:
服务器必须是Windows操作系统 —— ⽬前之所以web项⽬多⽤Java开发,就是因为服务器可以是Linux、Unix等⾮Windows的系统来降低项⽬的成本。
服务器上必须安装Office —— Jacob的意思就是: Java COM Bridge,java中调⽤office提供的com接⼝来实现对Office⽂件的操作。
并发问题 —— 如果多⽤户同时在线⽣成word⽂件就必须处理此并发问题,稍有不慎,就会在服务器端产⽣Office的死进程,死锁服务器的内存资源。
我遇到的问题是下载并合并附件,这⾥的附件⼤多是doc⽂件,也包含少量的docx⽂件,但是⽂件路径是从数据库中读取出来的,均不带后缀名,传统的xwpfdocument和hwpfdocument不能完全解决我的问题;尤其是将⽂件合并,不能轻易办到,需要对⽂档进⾏解析。
这⾥我采⽤的⽅法是将Word⽂件转换为HTML⽂件,把Word的合并转化为HTML的合并;这样⼀来就减
少了难度,不过就是还需要再把HTML⽂件转化为doc⽂件或者docx⽂件(此时,你就可以指定是哪种⽂件了)。
在转换的时候,分两个⽅向,⼀个是doc⽂件转换,另⼀个是docx⽂件转换;这⾥的转换时必须包含⽂档中的格式的(图⽚和表格我这⾥没有进⾏测试)。如果是没有⽂件后缀,那么就需要先判断是doc⽂件还是docx⽂件,这⾥⽤到了⼀个⼯具类,就是通过⽂件的⽂件头来判断⽂件类型,因为我这⾥只是为了区别doc和docx,所以就⽐较了前四位的16进制数,按照if和else来⾛两条转换路线。(具体⽂件的⽂件头可上⽹查资料,各种⽂件都有)。
转换doc⽂件的时候,是按照字符读取的,判断每个字符的字体颜⾊和样式,将其转换为HTML的代码,最后应该是整个稳当的HTML的字符串的累加,因为我这⾥是合并,所以我使⽤for循环进⾏了⽂件主体的叠加,最后在循环的外⾯加上HTML的头部和尾部信息即可。除此之外,根据需求,需要在不同⽂档之间插⼊分页符,分页符⽤HTML代码可以表⽰,"<br clear=all style='page-break-before:always' mce_style='page-break-before:always'> ";需要的直接添加即可。
然后是docx⽂件的转换,这⾥的就不像doc⽂件可以按照每个字符来读了,⽽是将整个⽂档直接转换为HTML⽂件,通过打印字符串可以得知,转换出来的HTML代码就是⼀个⼤的div,如果直接使⽤这个代码,合并的时候格式就不统⼀了,所以需要将图中的style样式去掉,直接⽤字符串截取,并加上⼀个空的<div>即可。
最后,再将HTML⽂件转为doc或者docx,可以将路径放在服务器上⾯,并且实现下载就⾏(建议每次下载完之后将该⽂件清空,可以循环利⽤)。详细代码如下。
package com.landray.kmss.km.doc.util;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;java修改html文件
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.del.PicturesTable;
import org.apache.poi.hwpf.usermodel.CharacterRun;
import org.apache.poi.hwpf.usermodel.Paragraph;
import org.apache.poi.hwpf.usermodel.Picture;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.hwpf.usermodel.Table;
import org.apache.poi.hwpf.usermodel.TableCell;
import org.apache.poi.hwpf.usermodel.TableIterator;
import org.apache.poi.hwpf.usermodel.TableRow;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
public class WordExcelToHtml {
/**
* 回车符ASCII码
*/
private static final short ENTER_ASCII = 13;
/**
* 空格符ASCII码
*/
private static final short SPACE_ASCII = 32;
/**
* ⽔平制表符ASCII码
*/
private static final short TABULATION_ASCII = 9;
// public static String htmlText = "";
public static String mainText = "";
public static String htmlTextTbl = "";
public static int counter = 0;
public static int beginPosi = 0;
public static int endPosi = 0;
public static int beginArray[];
public static int endArray[];
public static String htmlTextArray[];
public static boolean tblExist = false;
public static void main(String argv[]) {
try {
String htmlText = "<html><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8' />"
+ "</head><body>"; //将每⼀个Word中的主体部分拿出来,合并之后加上HTML的头和尾,但是要注意编码 List<String> list = new ArrayList<String>();
String file1 = "D://file8";
String file2 = "D://file9";
String file3 = "D://file11";
list.add(file1);
list.add(file2);
list.add(file3);
// String mainText1 = "";
for (int i = 0; i < list.size(); i++) {
htmlText += (i))
+ "<br clear=all style='page-break-before:always' mce_style='page-break-before:always'> ";
//每⼀个⽂档读取完之后,加上⼀个分页符,继续累加
}
htmlText += "</body></html>";
String filePath = "D://1.html";
writeFile(htmlText, filePath);
new HtmlToDoc().writeWordFile(filePath, "D://file10.doc");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 读取每个⽂字样式
*
* @param fileName
* @throws Exception
*/
public static String getWordAndStyle(String fileName) throws Exception {
String htmlText = "";
FileInputStream in = new FileInputStream(new File(fileName));
//根据⽂本内容判断是doc还是docx
byte[] b = new byte[4];
in.close();
FileInputStream in1 = new FileInputStream(new File(fileName));
System.out.println(bytesToHexString(b) + ";;;");
if (bytesToHexString(b).equalsIgnoreCase("d0cf11e0")) {//"d0cf11e0"代表的是doc⽂件
HWPFDocument doc = new HWPFDocument(in1);
Range rangetbl = Range();// 得到⽂档的读取范围
TableIterator it = new TableIterator(rangetbl);
int num =1;
beginArray = new int[num];
endArray = new int[num];
htmlTextArray = new String[num];
readTable(it, rangetbl);
// 取得⽂档中字符的总数
int length = doc.characterLength();
/
/ 创建图⽚容器;
PicturesTable pTable = PicturesTable();
int cur = 0;
String tempString = "";
for (int i = 0; i < length - 1; i++) {
// 整篇⽂章的字符通过⼀个个字符的来判断,range为得到⽂档的范围
Range range = new Range(i, i + 1, doc);
CharacterRun cr = CharacterRun(0);
if (tblExist && cur < beginArray.length) {
if (i == beginArray[cur]) {
htmlText += tempString + htmlTextArray[cur];
tempString = "";
i = endArray[cur] - 1;
cur++;
continue;
}
}
if (pTable.hasPicture(cr)) {
//htmlText += tempString;
// 读写图⽚
tempString = readPicture(pTable, cr);
//tempString = "";
htmlText += tempString;
} else {
Range range2 = new Range(i + 1, i + 2, doc);
// 第⼆个字符
CharacterRun cr2 = CharacterRun(0);
char c = cr.text().charAt(0);
// 判断是否为回车符
if (c == ENTER_ASCII) {
tempString += "<br/>";
}
// 判断是否为空格符
else if (c == SPACE_ASCII)
tempString += " ";
// 判断是否为⽔平制表符
else if (c == TABULATION_ASCII)
tempString += " ";
// ⽐较前后2个字符是否具有相同的格式
boolean flag = compareCharStyle(cr, cr2);
String fontStyle = "<span class='text' style=\"font-family:" + cr.getFontName()
+ ";font-size:"
+ cr.getFontSize()
/ 2
+ "pt;color:"
+ Ico24()) + ";";
if (cr.isBold())
fontStyle += "font-weight:bold;";
if (cr.isItalic())
fontStyle += "font-style:italic;";
htmlText += fontStyle + "\" mce_style=\"font-family:"
+ cr.getFontName() + ";font-size:"
+ cr.getFontSize() / 2 + "pt;";
if (cr.isBold())
fontStyle += "font-weight:bold;";
if (cr.isItalic())
fontStyle += "font-style:italic;";
htmlText += fontStyle + "\">" + tempString + cr.text()
+ "</span>";
tempString = "";
}
}
htmlText += tempString;
return htmlText;
} else {
Word2007ToHtml w = new Word2007ToHtml();
String filepath = "";
String fileName1 = fileName;
String htmlName = "D://3.html";
w.Word2007ToHtml(fileName1, htmlName);
String result = w.readFileByBytes(htmlName);
int i = result.indexOf('>');
String realreasult = "<div>"+result.substring(i+1);
System.out.println(realreasult);
htmlText += realreasult;
return htmlText;
}
}
/**
* 读写⽂档中的表格
*
* @param pTable
* @param cr
* @throws Exception
*/
public static void readTable(TableIterator it, Range rangetbl)
throws Exception {
htmlTextTbl = "";
/
/ 迭代⽂档中的表格
counter = -1;
while (it.hasNext()) {
tblExist = true;
htmlTextTbl = "";
Table tb = (Table) it.next();
beginPosi = tb.getStartOffset();
endPosi = tb.getEndOffset();
System.out.println("............" + beginPosi + "...." + endPosi);
counter = counter + 1;
// 迭代⾏,默认从0开始
beginArray[counter] = beginPosi;
endArray[counter] = endPosi;
htmlTextTbl += "<table border='1'>";
for (int i = 0; i < tb.numRows(); i++) {
TableRow tr = tb.getRow(i);
htmlTextTbl += "<tr >";
// 迭代列,默认从0开始
for (int j = 0; j < tr.numCells(); j++) {
TableCell td = tr.getCell(j);// 取得单元格
int cellWidth = td.getWidth();
// 取得单元格的内容
for (int k = 0; k < td.numParagraphs(); k++) {
Paragraph para = td.getParagraph(k);
String s = ().toString().trim();
if (s == "") {
s = " ";
}
System.out.println(s);
htmlTextTbl += "<td class='text' width=" + cellWidth
+ ">" + s + "</td>";
System.out.println(i + ":" + j + ":" + cellWidth + ":"
+ s);
} // end for
} // end for
} // end for
htmlTextTbl += "</table>";
htmlTextArray[counter] = htmlTextTbl;
} // end while
}
/**
* 读写⽂档中的图⽚
*
* @param pTable
* @param cr
* @throws Exception
*/
public static void readPicture(PicturesTable pTable, CharacterRun cr)
throws Exception {
// 提取图⽚
Picture pic = actPicture(cr, false);
// 返回POI建议的图⽚⽂件名
String afileName = pic.suggestFullFileName();
OutputStream out = new FileOutputStream(new File("e://test"
+ File.separator + afileName));
pic.writeImageContent(out);
// htmlText += "<img src=\"e://test//" + afileName
// + "\" mce_src=\"e://test//" + afileName + "\"/>";
}
public static boolean compareCharStyle(CharacterRun cr1, CharacterRun cr2) { boolean flag = false;
if (cr1.isBold() == cr2.isBold() && cr1.isItalic() == cr2.isItalic()
&& FontName().FontName())
&& FontSize() == FontSize()) {
flag = true;
}
return flag;
}
/**
* 写⽂件
*
* @param s
*/
public static void writeFile(String s, String filePath) {
FileOutputStream fos = null;
BufferedWriter bw = null;
try {
File file = new File(filePath);
fos = new FileOutputStream(file);
bw = new BufferedWriter(new OutputStreamWriter(fos)); bw.write(s);
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try {
if (bw != null)
bw.close();
if (fos != null)
fos.close();
} catch (IOException ie) {
}
}
}
// 判断⽂件类型
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder();
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = HexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
String();
}
}
获取字体颜⾊的⼯具类:
package com.landray.kmss.km.doc.util;
public class ColorUtils {
public static int red(int c) {
return c & 0XFF;
}
public static int green(int c) {
return (c >> 8) & 0XFF;
}
public static int blue(int c) {
return (c >> 16) & 0XFF;
}
public static int rgb(int c) {
return (red(c) << 16) | (green(c) <<8) | blue(c);
}
public static String rgbToSix(String rgb) {
int length = 6 - rgb.length();
String str = "";
while(length > 0){
str += "0";
length--;
}
return str + rgb;
}
public static String getHexColor(int color) {
color = color == -1 ? 0 : color;
int rgb = rgb(color);
return "#" + HexString(rgb));
}
}
将HTML⽂件转换为doc⽂件:
package com.landray.kmss.km.doc.util;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论