合并.doc和docx格式的Word文件

注:摘录自 https://www.cnblogs.com/shenzhouyh/articles/7243805.html

之前用过jacob 合并.doc,但是这种只能在windows环境使用,所以弃用了,下面这种方法打开word是html格式的

我遇到的问题是下载并合并附件,这里的附件大多是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;

import java.util.ArrayList;

import java.util.List;

import org.apache.poi.hwpf.HWPFDocument;

import org.apache.poi.hwpf.model.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 += getWordAndStyle(list.get(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.read(b, 0, b.length);

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 = doc.getRange();// 得到文档的读取范围

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 = doc.getPicturesTable();

int cur = 0;

String tempString = "";

for (int i = 0; i < length - 1; i++) {

// 整篇文章的字符通过一个个字符的来判断,range为得到文档的范围

Range range = new Range(i, i + 1, doc);

CharacterRun cr = range.getCharacterRun(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 = range2.getCharacterRun(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:"

+ ColorUtils.getHexColor(cr.getIco24()) + ";";

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 = para.text().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 = pTable.extractPicture(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()

&& cr1.getFontName().equals(cr2.getFontName())

&& cr1.getFontSize() == cr2.getFontSize()) {

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 = Integer.toHexString(v);

if (hv.length() < 2) {

stringBuilder.append(0);

}

stringBuilder.append(hv);

}

return stringBuilder.toString();

}

}

获取字体颜色的工具类:

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 "#" + rgbToSix(Integer.toHexString(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;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStreamReader;

import java.nio.charset.Charset;

import org.apache.poi.poifs.filesystem.DirectoryEntry;

import org.apache.poi.poifs.filesystem.DocumentEntry;

import org.apache.poi.poifs.filesystem.POIFSFileSystem;

//将docx文件转为HTML

package com.landray.kmss.km.doc.util;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.io.OutputStream;

import java.io.Reader;

import org.apache.poi.xwpf.usermodel.XWPFDocument;

import org.apache.poi.xwpf.converter.core.FileImageExtractor;

import org.apache.poi.xwpf.converter.core.FileURIResolver;

import org.apache.poi.xwpf.converter.xhtml.XHTMLConverter;

import org.apache.poi.xwpf.converter.xhtml.XHTMLOptions;

import org.junit.Test;

public  class Word2007ToHtml{

@Test

public void Word2007ToHtml(String fileName,String htmlName) throws IOException {

final String file = fileName;

File f = new File(file);

if (!f.exists()) {

System.out.println("Sorry File does not Exists!");

} else {

// ) 加载word文档生成 XWPFDocument对象

InputStream in = new FileInputStream(f);

XWPFDocument document = new XWPFDocument(in);

// ) 解析 XHTML配置 (这里设置IURIResolver来设置图片存放的目录)

File imageFolderFile = new File("D://");

XHTMLOptions options = XHTMLOptions.create().URIResolver(new FileURIResolver(imageFolderFile));

options.setExtractor(new FileImageExtractor(imageFolderFile));

options.setIgnoreStylesIfUnused(false);

options.setFragment(true);

// ) 将 XWPFDocument转换成XHTML

File file1 = new File(htmlName);

OutputStream out = new FileOutputStream(file1);

XHTMLConverter.getInstance().convert(document, out, options);

//也可以使用字符数组流获取解析的内容

//                ByteArrayOutputStream baos = new ByteArrayOutputStream();

//                XHTMLConverter.getInstance().convert(document, baos, options);

//                String content = baos.toString();

//                System.out.println(content);

//                 baos.close();

}

}

public static void main(String[] args) throws IOException {

Word2007ToHtml w = new Word2007ToHtml();

String fileName = "D://file1.docx";

String htmlName = "D://3.html";

w.Word2007ToHtml(fileName,htmlName);

String result = readFileByBytes(htmlName);

System.out.println(result);

}

public static String readFileByBytes(String fileName) {

String s="";

File file = new File(fileName);

Reader reader = null;

try {

//System.out.println("以字符为单位读取文件内容,一次读一个字节:");

// 一次读一个字符

reader = new InputStreamReader(new FileInputStream(file),"utf-8");

int tempchar;

while ((tempchar = reader.read()) != -1) {

// 对于windows下,\r\n这两个字符在一起时,表示一个换行。

// 但如果这两个字符分开显示时,会换两次行。

// 因此,屏蔽掉\r,或者屏蔽\n。否则,将会多出很多空行。

if (((char) tempchar) != ‘\r‘) {

s +=(char) tempchar;

}

}

reader.close();

} catch (Exception e) {

e.printStackTrace();

}

return s;

}

}

/**    * 将html文档转为doc    * @author soildwang   *   */

public class HtmlToDoc {

/**

* 读取html文件到word           *

* @param filepath html文件的路径           * @return

* * @throws Exception           */

public boolean writeWordFile(String filepath,String outfile) throws Exception {

boolean flag = false;

ByteArrayInputStream bais = null;

FileOutputStream fos = null;

//String outfile = "D://file8.doc";  //根据实际情况写路径

try {

if (!"".equals(outfile)) {

File fileDir = new File(outfile);

if (fileDir.exists()) {

String content = readFile(filepath);

byte b[] = content.getBytes();

bais = new ByteArrayInputStream(b);

POIFSFileSystem poifs = new POIFSFileSystem();

DirectoryEntry directory = poifs.getRoot();

DocumentEntry documentEntry =  directory.createDocument("WordDocument", bais);

fos = new FileOutputStream(outfile);

poifs.writeFilesystem(fos);

bais.close();

fos.close();

}

}

} catch (IOException e) {

e.printStackTrace();

} finally {

if(fos != null) fos.close();

if(bais != null) bais.close();

}                 return flag;

}

/**

* * 读取html文件到字符串           * @param filename

* * @return           * @throws Exception

* */

public String readFile(String filename) throws Exception {

StringBuffer buffer = new StringBuffer("");

BufferedReader br = null;

try {

br = new BufferedReader(new InputStreamReader(new  FileInputStream(new File(filename)),Charset.forName("utf-8")));

buffer = new StringBuffer();

while (br.ready())

buffer.append((char) br.read());

} catch (Exception e) {

e.printStackTrace();

} finally {

if(br!=null) br.close();

}

return buffer.toString();

}

//局部测试

public static void main(String[] args) throws Exception {

new HtmlToDoc().writeWordFile("d://1.html","D://file8.doc");//根据实际情况写文件路径

}

}

原文地址:https://www.cnblogs.com/muliu/p/12146186.html

时间: 2024-08-07 11:00:28

合并.doc和docx格式的Word文件的相关文章

Python:读取 .doc、.docx 两种 Word 文件简述及“Word 未能引发事件”错误

Python 中可以读取 word 文件的库有 python-docx 和 pywin32.   优点 缺点 python-docx 跨平台 只能处理 .docx 格式,不能处理.doc格式 pywin32 仅限 windows 平台 .doc 和 .docx 都能处理 pywin32 这个库很强大,不仅仅可以读取 word,但是网上介绍用 pywin32 读取 .doc 的文章真不多,因为,真心不好用. 以下是 pywin32 读取 .doc 的代码示例,但是读取表格有问题,输出全是空,原因不

基于java处理.docx格式的word合并

如下实例是将 2.docx和3.docx合并,写到empty.docx中,不适用于.doc格式, public static void main(String[] args) { File file1 = new File("D:\\empty.docx"); List<File> targetFile1 = new ArrayList<>(); targetFile1.add(new File("D:\\2.docx")); targetF

【jacob word】使用jacob,合并多个word为一个word文件

将几个word文件合并到一个word文件,使用注意点: 1.后面附项目运用的jar包jacob-1.9, 2.并且jacob运用中,需要将附件内的jacob.dll放到windows/system32下 语法介绍: 将一个关于JACOB的代码分成下面几个步骤: 1) ActiveXComponent ax = new ActiveXComponent("a1")://构建ActiveX组件实例 其中的a1的值和你需要调用的ActiveX控件有关 MS控件名 a1的值 InternetE

python通过docx模块解决doc及docx后缀文件内容的处理

import os,shutil,docx,re,time from win32com import client as wc #从所有级联目录读取文件到指定目录内 def count_files(file_dir): count=0 for p,d,f in os.walk(file_dir): for c in f: if c.split('.')[-1]=="doc": count +=1 src_dir = os.path.join(p, c) print(src_dir) d

java使用poi读取doc和docx文件

这几天在学习java io流的东西,有一个网友看到博客后问了一个问题,就是说他的doc文档为什么用我所说的方法死活就是乱码. 我一开始以为是他方法问题,结果自己试了之后发现和他的结果一样也是乱码. 于是在网上搜寻了一阵之后才发现原来doc文档和excel一样不能用普通的io流的方法来读取,而是也需要用poi,于是进行了一番尝试后,终于以正确的编码格式读取了这个doc文件. 在网上搜索的过程中发现doc和docx的读取方法是不一样的,于是顺带也学了一下docx文件的简单读取. 一.导包: doc文

python处理word文件:win32com用法详解

目标:用python处理doc文件 方法:引入win32com模块 ************************************************************************** 一.安装 ************************************************************************** 首先要先下载安装win32com模块(起先在linux下装不成功,后在windows下面成功了...) 下载地址:http

Java读取word文件的程序演示

完成对office文件的操作可以借助apache.poi包(我用的poi-3.10-FINAL),导入相应的jar包(最好全部导入) 下面的程序演示了一些操作word的过程,详细的函数功能可以查看此包的官方API import java.io.*; import org.apache.poi.POIXMLDocument; import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.hwpf.extractor.*; import

java读word文件

Java POI 读取word文件 Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能. 1.读取word 2003及word 2007需要的jar包 读取 2003 版本(.doc)的word文件相对来说比较简单,只需要 poi-3.5-beta6-20090622.jar 和 poi-scratchpad-3.5-beta6-20090622.jar 两个 jar 包即可, 而 2007 版本(.

freemarker根据模板生成word文件实现导出功能

一.准备工作 1.创建一个03的word文档,动态的数据用占位符标志占位(如testname).然后另存为word2003的xml文件. 2.格式化xml文件,占位符的位置用${testname}代替,若有多行格式相同数据等,用List循环. 注意:不要用Eclipse工具去格式化xml文件(会导致导出的word文件不能用office软件打开,但是PDF能打开,估计是pdf的容错率高于office),推荐使用firstObject工具格式化xml文件. 3.将xml文件(也可以改成ftl格式)存