使用Jacob与Word文件交互

摘要:
转移自:http://www.blogjava.net/lonsy/archive/2009/01/09/250713.htmlJacob项目官方地址:Http://sourceforge.net/projects/jacob-project/官方介绍:JACO比萨JAVA COM桥,允许您从J调用COM自动化组件

转自:http://www.blogjava.net/lonsy/archive/2009/01/09/250713.html

Jacob项目的官方地址: Http://sourceforge.net/projects/jacob-project/
官方介绍:
    JACOB is a JAVA-COM Bridge that allows you to call COM Automation components from Java. It uses JNI to make native calls to the COM libraries. JACOB runs on x86 and x64 environments supporting 32 bit and 64 bit JVMs
它是一个使用jni来调用com组件及其库文件的工具。这里仅介绍处理word文档。

首先要部署其dll文件。jacob-1.14.3-x86.dll 或 jacob-1.14.3-x64.dll,下载的文件解压后即可看到。我是直接将dll文件放在windowssystem32目录下的,方便,当然也有其他做法。
其次,就是把其jar文件路径加入Windows路径中。
接着就可以在你的Java程序中调用了。我总结下大概有下面几个阶段:

1. 初始化相关参数,代码如下:

// 打开Word应用程序
ActiveXComponent app = new ActiveXComponent("Word.Application");
// 设置word不可见
app.setProperty("Visible", new Variant(false));
// 打开word文件
Dispatch word = app.getProperty("Documents").toDispatch();
Dispatch doc = Dispatch.invoke(word, "Open", Dispatch.Method, new Object[] {"File Name", new Variant(false), new Variant(false) }, new int[1]).toDispatch();
//获取指针
Dispatch cursor = app.getProperty("Selection").toDispatch();


如上,我们打开了一个名为File Name的word文件,你可能会觉得最后那句看起来很繁琐,是的,有更好的代替方式,如下:

Dispatch doc = Dispatch.call(word, "Open", new Variant(false), new Variant(false)).toDisptach();


这正是Jacob给我们提供的两种调用方式。

2. 处理word文档,如果你先前有VBA相关开发经验,那就简单了。没有的也没事,打开office程序目录下的2052VBAWD10.chm,这里有Word的对象模型的所有记录。
接着讲述下Jacob中两种最常用的类型:
Variant:这是一种可变的类型,用于Jacob中几乎所有函数的返回值,并可转换为其他任何类型,包括Java基本类型。当然,应该按需要与规则来。
Dispatch:Object represents MS level dispatch object. Each instance of this points at some data structure on the MS windows side.就是说可以代表所有对象模型。
有所了解后我们来看对模型的处理方式。
当我们获得一个模型后,如前面打开的doc文档,均已转换成一个Dispatch对象。只有转换后才能读取、设置其属性,或者调用其方法,如下:

//获取其属性,表格的集合
Dispatch tables = Dispatch.get(doc, "Tables").toDispatch();
//调用方法取得其中的第一张表格
Dispatch table = Dispatch.call(this.tables, "Item", new Variant(0)).toDispatch();
//修改此表格第一行第一列的单元格
Dispatch cell = Dispatch.call(table,"Cell", Integer.toString(1), Integer.toString(1)).toDispatch();
Dispatch.call(cell, "Select");
Dispatch.put(cursor, "Text", "New String");


这就是简单的处理,更多的还是多了解了解对象模型吧

3. 关闭文档及进程

//关闭文档且不保存
Dispatch.call(doc, "Close", new Variant(false));
//退出进程对象
app.invoke("Quit", new Variant[] {});


更多请参看下载文件中的API帮助文档.. 

下面是我写的类,用于封装其功能。(注意,这个类并没有涉及多个word文档线程的处理)

import com.jacob.com.*;
import com.jacob.activeX.*;

/**
 *
 * @author Lonsy
 */
public class WordHandle {
    
    //运行时的Word程序
    private ActiveXComponent app;

    //word对象
    private Dispatch words;

    //当前的word文档
    private Dispatch doc;

    //当前光标位置
    private Dispatch cursor;

    //当前文档是否只读
    private boolean readOnly;

    //当前文档中所有表格
    private Dispatch tables;

    //当前所在表格
    private Dispatch table;

    private int count;

    public WordHandle()
    {
        this.app = new ActiveXComponent("Word.Application");
        this.app.setProperty("Visible", new Variant(false));    // 设置word不可见
        words = this.app.getProperty("Documents").toDispatch();
        this.doc = null;
        this.cursor = null;
        this.readOnly = true;
        this.count = 0;
    }

    /**
     * 打开word文件
     * @param fileName 文件名,使用绝对路径
     * @param readOnly 是否只读
     * @return
     * @throws java.lang.Exception
     */
    public boolean open(String fileName, boolean readOnly) throws Exception
    {
        if (doc != null)
        {
            System.out.println("当前文件未关闭");
            return false;
        }
        this.doc = Dispatch.invoke(this.words, "Open", Dispatch.Method, new Object[] {fileName, new Variant(false), new Variant(readOnly)}, new int[1]).toDispatch();
        this.cursor = app.getProperty("Selection").toDispatch();
        this.tables = Dispatch.get(this.doc,"Tables").toDispatch();
        this.readOnly = readOnly;
        this.count = Dispatch.get(Dispatch.get(this.doc, "Words").toDispatch(), "Count").getInt() - 1;
        System.out.println("打开文件" + fileName + (readOnly ? " ReadOnly" : " Writable"));
        return true;
    }

    /**
     * 建立新的Word文件
     * @return
     * @throws java.lang.Exception
     */
    public boolean newFile() throws Exception
    {
        if (doc != null)
        {
            System.out.println("当前文件未关闭");
            return false;
        }
        this.doc = Dispatch.call(this.words, "Add").toDispatch();
        this.readOnly = false;
        this.cursor = app.getProperty("Selection").toDispatch();
        this.tables = Dispatch.get(this.doc,"Tables").toDispatch();
        System.out.println("新建word文档");
        return true;
    }

    /**
     * 关闭当前文件,并不保存
     * @return
     */
    public boolean close()
    {
        String fileName = null;
        if (this.doc != null)
        {
            try
            {
                fileName = Dispatch.get(this.doc, "Name").getString();
                Dispatch.call(this.doc, "Close", new Variant(false));
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            finally
            {
                this.doc = null;
            }
        }
        System.out.println("关闭文件 " + fileName);
        return true;
    }

    /**
     * 退出
     * @return
     */
    public boolean quit()
    {
        try
        {
            this.app.invoke("Quit", new Variant[] {});
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        System.out.println("退出word");
        return true;
    }

    /**
     * 另存为
     * @param fileName 目标文件名,为绝对路径
     * @return
     */
    public boolean saveAs(String fileName) throws Exception
    {
        if (this.doc == null)
        {
            System.out.println("当前无文件");
            return false;
        }
        else
        {
            Dispatch.call(this.doc, "SaveAs", fileName);
            System.out.println("另存为" + fileName);
            return true;
        }
    }

    /**
     * 保存
     * @return
     */
    public boolean save() throws Exception
    {
        if (this.doc == null)
        {
            System.out.println("当前无文档,无法保存");
            return false;
        }
        else
        {
            if (this.readOnly)
            {
                System.out.println("只读文档,保存失败");
                return false;
            }
            Dispatch.call(this.doc, "Save");
            System.out.println("保存完成");
            return true;
        }
    }

    /**
     * 将光标或选定内容向右移动
     * @param step
     * @return
     */
    public boolean moveRight(int steps) throws Exception
    {
        //int start = Dispatch.get(this.cursor, "Start").getInt();
        //Dispatch.put(this.cursor, "Start", start + steps);
        for (int i=0; i<steps; i++)
        {
            Dispatch.call(cursor, "MoveRight");
        }
        return true;
    }

    /**
     * 将光标或选定内容向左移动
     * @param step
     * @return
     */
    public boolean moveLeft(int steps) throws Exception
    {
        for (int i=0; i<steps; i++)
        {
            Dispatch.call(cursor, "MoveLeft");
        }
        return true;
    }

    /**
     * 从当前位置起查找指定内容,并将光标移到相应位置上
     * @param str
     * @return 光标位置,未找到则为0
     * @throws java.lang.Exception
     */
    public int search(String str) throws Exception
    {
        // 从cursor所在位置开始查询
        Dispatch find = Dispatch.call(this.cursor, "Find").toDispatch();
        // 设置要查找的内容
        Dispatch.put(find, "Text", str);
        // 向前查找
        Dispatch.put(find, "Forward", "True");
        // 设置格式
        Dispatch.put(find, "Format", "True");
        // 大小写匹配
        Dispatch.put(find, "MatchCase", "True");
        // 全字匹配
        Dispatch.put(find, "MatchWholeWord", "True");
        // 查找
        if (!Dispatch.call(find,"Execute").getBoolean())
            return 0;
        else
        {
            return Dispatch.get(this.cursor, "Start").getInt();
        }
    }

    /**
     * 从当前位置起查找指定内容,并只将光标开始处移到相应位置上
     * @param str
     * @return 光标位置,未找到则为0
     * @throws java.lang.Exception
     */
    public int searchOnly(String str) throws Exception
    {
        // 从cursor所在位置开始查询
        Dispatch find = Dispatch.call(this.cursor, "Find").toDispatch();
        // 设置要查找的内容
        Dispatch.put(find, "Text", str);
        // 向前查找
        Dispatch.put(find, "Forward", "True");
        // 大小写匹配
        Dispatch.put(find, "MatchCase", "True");
        // 全字匹配
        Dispatch.put(find, "MatchWholeWord", "True");
        if (!Dispatch.call(find,"Execute").getBoolean())
            return 0;
        else
        {
            int start = Dispatch.get(this.cursor, "Start").getInt();
            Dispatch.put(this.cursor, "End", this.count);
            //System.out.println(start);
            return start;
        }
    }

    public String getBetween(int start, int end) throws Exception
    {
        Dispatch range = Dispatch.get(this.cursor, "Range").toDispatch();
        Dispatch.call(range,"SetRange", start, end);
        return Dispatch.get(range, "Text").getString();
    }

    public String getLineAfter(int start) throws Exception
    {
        Dispatch.put(this.cursor, "Start", start);
        int length = Dispatch.call(this.cursor, "EndKey").getInt() + start;
        return getBetween(start, length);
    }

    public String getLine(int position) throws Exception
    {
        Dispatch.put(this.cursor, "Start", position);
        Dispatch.call(this.cursor, "SelectRow");
        int start = Dispatch.get(this.cursor, "Start").getInt();
        int end = Dispatch.get(this.cursor, "End").getInt();
        return getBetween(start, start + end);
    }

    public boolean gotoPage(int index) throws Exception
    {
        Dispatch.invoke(this.cursor, "Goto", Dispatch.Method, new Object[] {1, 2, String.valueOf(index)}, new int[1]);
        //Dispatch.call(this.cursor, "GoTo", "wdGoToLine", "wdGoToNext", String.valueOf(index), null);
        return true;
    }

    public int getCurrentCursor() throws Exception
    {
        return Dispatch.get(this.cursor, "Start").getInt();
    }

    public boolean setCursorMode() throws Exception
    {
        Dispatch.put(this.cursor, "End", Dispatch.get(this.cursor, "Start").getInt());
        return true;
    }

    public boolean gotoHome() throws Exception
    {
        Dispatch.put(this.cursor, "Start", 0);
        return true;
    }

    /**
     * 在光标后指定便宜插入字符串,并将光标移到新位置
     * @param str
     * @return
     * @throws java.lang.Exception
     */
    public boolean insert(int steps, String str) throws Exception
    {
        int start = Dispatch.get(this.cursor, "Start").getInt() + steps;
        Dispatch.put(this.cursor, "Start", start);
        Dispatch.call(this.cursor, "InsertBefore", str);
        this.getCount();
        Dispatch.put(this.cursor, "Start", start + str.length());
        //System.out.println(Dispatch.get(this.cursor, "Start").getInt() + "   " + (Dispatch.get(this.cursor, "Start").getInt()+Dispatch.get(this.cursor, "End").getInt()));
        return true;
    }

    /**
     * 用指定的字符串替代当前选定的内容
     * @param str
     * @return
     * @throws java.lang.Exception
     */
    public boolean replace(String str) throws Exception
    {
        Dispatch.put(this.cursor, "Text", str);
        return true;
    }

    /**
     * 获取当前文档中的表格数
     * @return
     * @throws java.lang.Exception
     */
    public int getTableNum() throws Exception
    {
        return Dispatch.get(this.tables, "Count").getInt();
    }
    
    /**
     * 设定当前工作表格
     * @param index
     * @return
     * @throws java.lang.Exception
     */
    public boolean setCurrentTable(int index) throws Exception
    {
        this.table = Dispatch.call(this.tables, "Item", new Variant(index)).toDispatch();
        Dispatch.call(this.table, "Select");
        return true;
    }
    
    /**
     * 获取指定单元格的内容
     * @param row
     * @param col
     * @return
     * @throws java.lang.Exception
     */
    public String getCell(int row, int col) throws Exception
    {
        Dispatch cell = Dispatch.call(table, "Cell", Integer.toString(row), Integer.toString(col)).toDispatch();
        Dispatch.call(cell,"Select");
        String tmp = Dispatch.get(this.cursor, "Text").getString();
        //System.out.println(".." + tmp);
        if (tmp.length() > 2)
        {
            return tmp.substring(0, tmp.length() - 2);
        }
        else
            return "";
    }

    /**
     * 用指定的字符串代替当前表格中指定的单元格
     * @param row
     * @param col
     * @param str
     * @return
     * @throws java.lang.Exception
     */
    public boolean replaceCell(int row, int col, String str) throws Exception
    {
        Dispatch cell = Dispatch.call(table,"Cell", Integer.toString(row), Integer.toString(col)).toDispatch();
        Dispatch.call(cell, "Select");
        Dispatch.put(this.cursor, "Text", str);
        return true;
    }
}

免责声明:文章转载自《使用Jacob与Word文件交互》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇VC动态轨迹画线【LOJ#10172】涂抹果酱下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

7.qml-Qt对象

QML除了支持ECMAScript内置对象对象外,还自己给用户提供了许多宿主对象.当然用户也可以自己自定义对象. 内置对象 : 由 ECMAScript所提供的对象;如Object、Array、Math、Date等等。 宿主对象 :即由 ECMAScript 实现的宿主环境提供的对象,比如Qt对象. 自定义对象 :自定义构造函数所创建的对象。 本章我们...

内网esxi磁盘空间不足导致虚拟机宕机

内网esxi磁盘空间不足导致虚拟机宕机 一、问题引入   周一上班的时候,发现公司内网的戴尔服务器上(前人装的ESXi系统,里面有很多个虚拟机),好几个虚拟机异常关机了。点击重新开机,有以下报错提示: 选Retry是没用的,选Cancel,才有可能开机,为啥叫可能,因为有一些空间占用多的虚拟机不一定能开机,会一直重复这种报错。 二、问题研究及解决   检...

.Net 文件名后缀的详细解释

KeyLife富翁笔记 作者:HongYuan标题: .Net 文件名后缀的详细解释 关键字:分类:个人专区密级: 公开 (评分: , 回复: 0, 阅读: 553) »» .sln:解决方案文件,为解决方案资源管理器提供显示管理文件的图形接口所需的信息。 .csproj:项目文件,创建应用程序所需的引用、数据连接、文件夹和文件的信息。...

史上最全的springmvc入参传递总结

一、springmvc的优势 1、springmvc能够将URL从http的世界中映射到JAVA世界中,这是框架的核心功能,不得不说确实很强大,但非常的容易理解。 2、springmvc对annotation的完没支持,去掉struts2及springbean繁琐的配置文件,提高开发效率。 3、springmvc结合jackson-core,action层...

如何计算每个基因的覆盖度与深度

 如何计算每个基因的覆盖度与深度,有多种方法可以完成。如下演示使用samtools depth命令方法   1. 数据下载 1.1 Fastq文件下载   从NCBI下载Illumina Hiseq X Ten平台的RNA-Seq数据SRR7751429信息如上图所示。 1.1.1 使用wget命令(sra-toolkit工具下载太慢)下载 wget f...

IDEA报Unable to save settings: Failed to save settings. Please restart IntelliJ IDEA随后闪退

解决方案 首先确保对config文件有读写权限 如果权限没问题,还是报错的话,那就做下一步。 查看log文件 找到出错原因,这里可能每个人的原因都不同。因此,解决方案也不同。 Memory Mapping Failed Cannot recover from OOME in memory mapping: -Xmx=998MB new size l...