Java文件操作系列[3]——使用jacob操作word文档

时间:2021-12-12 18:17:48

Java对word文档的操作需要通过第三方组件实现,例如jacob、iText、POI和java2word等。
jacob组件的功能最强大,可以操作word,Excel等格式的文件。该组件调用的的是操作系统底层的dll文件。在使用Java操作word文件时,jacob组件是最常用的一个。

1.准备工作

  根据上面的描述,需要两类文件、一个软件:

  ①jacob.jar

  ②dll文件

  下载地址1:百度云盘下载

  下载地址2:官方下载

  ③电脑上有Microsoft Office软件(WPS、LibreOffice未经试验)。

2.开始编程

Java文件操作系列[3]——使用jacob操作word文档Java文件操作系列[3]——使用jacob操作word文档
 1 package com.myeclipse;  2 
 3 import com.jacob.activeX.ActiveXComponent;  4 import com.jacob.com.Dispatch;  5 import com.jacob.com.Variant;  6 
 7 /**
 8  * 使用jacob操作word文档  9  * @author MrChen 10  * 11  */
12 public class JacobOperateDoc{ 13 
14     
15     private ActiveXComponent MSWordApp = null;    //声明一个word对象
16     private Dispatch document = null; 17 
18 
19     /**
20  * 打开word文档 21  * @param makeVisible 是否以可读写方式打开 22      */
23     public void  openWord( boolean makeVisible) { 24         if( MSWordApp == null ) { 25             MSWordApp = new ActiveXComponent("Word.Application"); 26  } 27         //设置visible
28         Dispatch.put(MSWordApp,"Visible",new Variant(makeVisible)); 29 
30  } 31     
32     /**
33  * 新建word文档 34      */
35     public void createNewDocument() { 36         //获取文档集合
37         Dispatch documents = Dispatch.get(MSWordApp, "Documents").toDispatch(); 38         //调用add方法向文档集合中添加一个新的Word文件
39         document = Dispatch.call(documents, "Add").toDispatch(); 40  } 41     
42     /**
43  * 向word中写入字符串 44  * @param text 45      */
46     public void insertText(String txt) { 47         //获取当前执行写入的位置,如果是新word文件操作位置为文档开始
48         Dispatch selection = Dispatch.get(MSWordApp, "Selection").toDispatch(); 49         //将字符串写入
50         Dispatch.put(selection, "Text", txt); 51  } 52     
53     /**
54  * 另存为 55  * @param fileName 56      */
57     public void saveFileAs(String fileName) { 58         Dispatch.call(document, "SaveAs",fileName); 59  } 60     
61     /**
62  * 打印 63      */
64     public void printFile() { 65         //采用默认打印机打印
66         Dispatch.call(document, "PrintOut"); 67  } 68     
69     /**
70  * 关闭文档 71  * @param type 72  * 0: 关闭文档不改变保存信息 73  * -1: 关闭文档改变保存信息 74  * -2: 关闭文档提示是否保存改变信息,请求确认 75      */
76     public void closeDocument(Integer type) { 77         //如果关闭类型不正确,则默认为
78         if((type!=0 && type!=-1 && type != -2) || type == null){ 79             type = -2; 80  } 81         Dispatch.call(document, "Close", new Variant(type)); 82         document = null; 83  } 84     
85     /**
86  * 退出 87      */
88     public void closeWord() { 89         Dispatch.call(MSWordApp, "Quit"); 90         MSWordApp = null; 91         document = null; 92  } 93 }
JacobOperateDoc
Java文件操作系列[3]——使用jacob操作word文档Java文件操作系列[3]——使用jacob操作word文档
 1 package com.myeclipse;  2 
 3 /**
 4  * 测试JacobOperateDoc类  5  * @author MrChen  6  *  7  */
 8 public class Test {  9 
10     /**
11  * @param args 12      */
13     public static void main(String[] args) { 14         System.out.println("start!"); 15         System.out.println(System.getProperty("java.library.path")); 16         JacobOperateDoc jac = new JacobOperateDoc(); 17         jac.openWord(true); 18  jac.createNewDocument(); 19         jac.insertText("helloworld!"); 20         jac.saveFileAs("D:\\hell.doc"); 21         try{ 22             jac.closeDocument(null); 23         }catch(NullPointerException e){ 24             //捕捉空指针异常,什么也不做
25  } 26  jac.closeWord(); 27         System.out.println("end!"); 28  } 29 
30 }
测试JacobOperateDoc类

3.遇见的问题及解决方案

  在研究jacob的过程中遇到了一些问题,导致笔者一度想放弃,但这种想法不过一秒而已。笔者一直坚持这样的观点:一件正确的事,既然开始了,就坚持到底,决不放弃!下面是对其中一些问题的摘录。

  (1) 执行Test类,报错Unsupported major.minor version 51.0

必要的资料:各JDK版本对应的错误编号如下:
  J2SE 8 = 52,
  J2SE 7 = 51,
  J2SE 6.0 = 50,
  J2SE 5.0 = 49,
  JDK 1.4 = 48,
  JDK 1.3 = 47,
  JDK 1.2 = 46,
  JDK 1.1 = 45。

    原因:通过搜寻到的JDK版本对应错误资料,可以得出结论:外部jar包使用jdk1.7(jdk7)编译,而使用此jar包的工程jdk版本为jdk1.6(jdk6),故版本不支持。

    解决目标:项目使用的JRE System Library和外用JDK版本保持一致。即修改后是这样的:

      Java文件操作系列[3]——使用jacob操作word文档

    解决步骤

      第一大步:修改JDK版本(注:这里本来是一个链接,但博客园非说这个链接有违禁内容,连直接把链接地址粘贴到这里里都不行......故啰嗦下怎么进行)

        ①修改Eclipse/Myeclipse JDK版本:Window ----> Preference ----> Java ----> Installed JREs。选择相应的JDK版本。

          Java文件操作系列[3]——使用jacob操作word文档

        ②修改项目的JDK编译版本:项目右键 ----> Java Compiler ----> Enable project specific settings。

          Java文件操作系列[3]——使用jacob操作word文档

        ③Window ----> Preference ----> Myeclipse ----> Servers ----> Resin ----> Resin3.x ----> JDK

          Java文件操作系列[3]——使用jacob操作word文档

      第二大步:修改JRE system library (点击查看参考文章)

      注:这两大步必不可少。

  (2) 解决完以上错误之后,执行Test类,出现异常Exception in thread "main" java.lang.UnsatisfiedLinkError: no jacob-1.18-x64 in java.library.path

    错误原因:path路径下找不到jacob-1.18-x64.dll文件

    解决方案

    ① 找到path路径。

      在Test类中增加输出:

System.out.println(System.getProperty("java.library.path")); 

      执行得到:

D:\Java\jdk1.7.0_80\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;D:/Program Files/MyEclipse-8.6/Common/binary/com.sun.java.jdk.win32.x86_1.6.0.013/jre/bin/client;  .......(还有很多,不再列举)

    ② 将dll文件复制到C:\Windows\system32路径之下。

    再次执行Test类,成功!

    画外音:通过输出path路径,同时也更清楚地看到,Java程序在运行的时候会从前往后扫描path路径,故在解决第一个错误之前使用的JDK版本是1.6。要是早将dll放在C:\Windows\system32路径之下,就不会出现这第二个异常了。

4.进一步了解jacob

   (1)jacob是个什么玩意?

     jacob一个Java-COM中间件。通过这个组件我们就可以在Java应用程序中调用COM组件和Win32程序库。

  (2)为什么我们用java去操纵office(如:word)要使用com,而不直接使用java去做?

    office是建立在windows平台之上的,本身是一个软件,除了他自己提供的宏似乎没有什么能对他进行直接的操作。

    在windows平台上为了解决像这样的不同应用软件,通信缺乏通用api问题,推出了com的解决方案。

    我们使用dll中的一组或多组相关的函数存取组件数据,总的合称为接口(对应jacob,就是Dispatch),具体到每个细节的实现称为方法。

    我们使用jacob就是通过一个接口来操作word的ActiveX对象(实质是调用指向接口的指针,这也是唯一途径)。

    总结一下,有这么几点:

      ①Java是与平台无关的语言,不能对平台软件做个性化的操作。

      ②Windows平台提供了com组件来通信,但是java语言不认识这个com组件,所以我们用jacob来架起java程序与com组件沟通(通信)的桥梁。(注:java与dll交互的技术主要有3种:JNI,jawin和jacob。后两种都是基于JNI。)

      同时这也说明了为什么本地应用没有office应用就无法进行的原因:如果没有office,则无法建立Java-COM桥,进而无法解析。

5.小结

  (1)JDK版本应该保持一致。

  (2)dll文件要放在C:\Windows\system32路径之下。

  (3)jacob.jar括两个部分:

    • com.jacob.activeX: ActiveXComponent类
    • com.jacob.com: 其它类和元素

  (4)Jacob类

  Jacob的结构很简单,包含以下几个类:

    • ActiveXComponent Class:封装了Dispatch对象,用于创建一个封装了COM组件对象的Java Object
    • Dispatch Class:用于指向封装后的MS数据结构。常用的方法有call,subcall,get,invoke…后面会介绍使用方法。
    • Variant Class:用于映射COM的Variant数据类型。提供Java和COM的数据交换。
    • ComException Class:异常类

  (5)Jacob方法

用于访问COM/DLL对象的方法,读取、修改COM/DLL对象的属性。

    • call method:属于Dispatch类。用于访问COM/DLL对象的方法。方法进行了重载,方便不同场合调用。返回一个Variant类型的值。
    • callSub method:使用方法和call一样,不过它不返回值。
    • get method:读取COM对象的属性值,返回一个Variant类型值。
    • put method:设置COM对象的属性值。
    • invoke method:call的另一种用法,更复杂一些。
    • invokesub method:subcall的另一种用法
    • getProperty method:属于ActiveXComponent类,读取属性值,返回一个Variant类型值。
    • setProperty method:属于ActiveXComponent类,设置属性值。

    注:API在下载里面也附带了(点击单独下载API)。