使用Jacob實現Word轉換Html
阿新 • • 發佈:2018-11-30
前言
源於一個專案的需求,使用者上傳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秒。