1. 程式人生 > >使用Jacob實現Word轉換Html

使用Jacob實現Word轉換Html

前言

       源於一個專案的需求,使用者上傳Word檔案後要能及時在網頁上檢視檔案內容,類似於QQ郵箱的附件檢視,QQ郵箱使用的是永中的產品工具。自己做當然是首選不要錢自己寫程式碼就能搞定的。網上搜索後找到了Jacob,下面記錄一下使用過程和自己使用中的一些心得。

環境

       在專案中引入jacob.jar。複製jacob-1.16.1-x86.dll到jdk\bin目錄,放置dll的位置網上有兩種說法,一種是jdk\bin另一種是system32。其實只要放在path目錄下即可,java中檢視path目錄的方式:System.getProperty("java.library.path")。另外切勿修改dll的檔名稱,因為jacob.jar中已經寫好了dll的名稱,改了dll的名稱後呼叫時就找不到了。下載的Jacob裡面一般會包含x86和x64兩個dll,使用哪一個是與jdk的版本相關的,與作業系統版本無關。

程式碼

常規方式

//word檔案路徑及名稱
String docPath = "D:\\download\\word\\1.docx";
//html檔案路徑及名稱
String fileName = "D:\\download\\html\\1.html";
//建立Word物件,啟動WINWORD.exe程序
ActiveXComponent app = new ActiveXComponent("Word.Application");
//設定用後臺隱藏方式開啟
app.setProperty("Visible", new Variant(false));
//獲取操作word的document呼叫
Dispatch documents = app.getProperty("Documents").toDispatch();
//呼叫開啟命令,同時傳入word路徑
Dispatch doc = Dispatch.call(documents, "Open", docPath).toDispatch();
//呼叫另外為命令,同時傳入html的路徑
Dispatch.invoke(doc, "SaveAs", Dispatch.Method, 
	new Object[] { fileName, new Variant(8) }, new int[1]);
//關閉document物件
Dispatch.call(doc, "Close", new Variant(0));
//關閉WINWORD.exe程序
Dispatch.call(app, "Quit");
//清空物件
doc = null;
app = null;

       如果word檔案包含圖片,那麼會生成與html同名的1.files資料夾。這與在IE瀏覽器中使用右鍵另存為網頁一樣。

       以上方式在每次呼叫時系統會建立WINWORD.exe程序,然後再關閉。要知道系統建立程序是非常耗資源的,時間和CPU。我做了一個簡單的測試,將1.docx檔案複製了30份,迴圈呼叫30次,用時76秒。

long start = System.currentTimeMillis();
JacobUtil jacobUtil = new JacobUtil();
for (int i = 1; i <= 30; i++) {
<span style="white-space:pre">	</span>jacobUtil.wordConvert("D:\\download\\word\\"+i+".docx", 
			"D:\\download\\html\\"+i+".html");
}
long end = System.currentTimeMillis();
System.out.println("用時:"+(end-start)/1000L+"秒");

單例方式

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;

public class JacobUtil {
	
	private static ActiveXComponent app;
	/**
	 * 單例模式
	 */
	public static ActiveXComponent getWordInstance(){
		if (app == null) {
			app = new ActiveXComponent("Word.Application");
			app.setProperty("Visible", new Variant(false));
		}
		return app;
	}
	/**
	 * 轉換word
	 */
	public static void wordConvertSingleton(String docPath, String fileName) {
		try {
			app = getWordInstance();
			Dispatch documents = app.getProperty("Documents").toDispatch();
			Dispatch doc = Dispatch.call(documents, "Open", docPath).toDispatch();
			Dispatch.invoke(doc, "SaveAs", Dispatch.Method, 
					new Object[] { fileName, new Variant(8) }, new int[1]);
			Dispatch.call(doc, "Close", new Variant(0));
			//沒有呼叫Quit命令
			doc = null;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
       單例方式將只有一個ActiveXComponet,那麼WINWORD.exe程序也只會有一個,不會重複建立關閉程序,而是一直使用這個程序。轉換30次,只需14秒。

long start = System.currentTimeMillis();
for (int i = 1; i <= 30; i++) {
<span style="white-space:pre">	</span>JacobUtil.wordConvertSingleton("D:\\download\\word\\"+i+".docx", 
		"D:\\download\\html\\"+i+".html");
}
long end = System.currentTimeMillis();
System.out.println("單例用時:"+(end-start)/1000L+"秒");

多執行緒方式

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;

public class ThreadConvert implements Runnable{

	private  ActiveXComponent app;
	private String docPath;
	private String fileName;
	
	public ThreadConvert(ActiveXComponent app,String docPath, String fileName) {
		this.app = app;
		this.docPath = docPath;
		this.fileName = fileName;
	}
	
	public void run() {
		System.out.println("開始:"+System.currentTimeMillis());
		try {
			app.setProperty("Visible", new Variant(false));
			Dispatch documents = app.getProperty("Documents").toDispatch();
			Dispatch doc = Dispatch.call(documents, "Open", docPath).toDispatch();
			Dispatch.invoke(doc, "SaveAs", Dispatch.Method, 
					new Object[] { fileName, new Variant(8) }, new int[1]);
			Dispatch.call(doc, "Close", new Variant(0));
			doc = null;
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("結束:"+System.currentTimeMillis());
	}
}
ActiveXComponent app1 = new ActiveXComponent("Word.Application");
for (int i = 1; i <= 30; i++) {
	Thread thread = new Thread(
		new ThreadConvert(app1,"D:\\download\\word\\"+i+".docx", 
				"D:\\download\\html\\"+i+".html"));
	thread.start();
}
       因為執行緒執行不好計時,使用的是找出最早的開始時間與最晚的結束時間相減是15秒,與單例方式相近。

多程序方式

ActiveXComponent app1 = new ActiveXComponent("Word.Application");
ActiveXComponent app2 = new ActiveXComponent("Word.Application");
ActiveXComponent app3 = new ActiveXComponent("Word.Application");
for (int i = 1; i <= 30; i++) {
<span style="white-space:pre">	</span>if (i<=10) {
		Thread thread = new Thread(new ThreadConvert(app1,"D:\\download\\word\\"+i+".docx", 
						"D:\\download\\html\\"+i+".html"));
		thread.start();
	}else if(i <= 20){
		Thread thread = new Thread(new ThreadConvert(app2,"D:\\download\\word\\"+i+".docx", 
						"D:\\download\\html\\"+i+".html"));
		thread.start();
	}else {
		Thread thread = new Thread(new ThreadConvert(app3,"D:\\download\\word\\"+i+".docx", 
						"D:\\download\\html\\"+i+".html"));
		thread.start();
	}
}
       使用三個ActiveXComponent,也就是三個WINWORD.exe程序,每個程序分配10個轉換任務,同樣用最早的開始時間與最晚的結束時間相減是9秒。