【问题标题】:Query Windows Search from Java从 Java 查询 Windows 搜索
【发布时间】:2009-04-23 00:15:42
【问题描述】:

我想从 Java 直接(或间接)查询 Windows Vista 搜索服务。

我知道可以使用 search-ms: 协议进行查询,但我想在应用程序中使用结果。

我在Windows Search API 中找到了很好的信息,但没有与 Java 相关的信息。

我会将提供有关如何实现此目标的有用和明确信息的答案标记为已接受。

提前致谢。

编辑

在我将其标记为已接受之前,是否有人有 JACOB 样本? :)

【问题讨论】:

    标签: java windows-search


    【解决方案1】:

    您可能想查看其中一种 Java-COM 集成技术。我亲自与 JACOB (JAva COM Bridge) 合作过:

    这相当麻烦(想想只使用反射),但为我完成了工作(概念的快速证明,从 Java 中访问 MapPoint)。

    我知道的唯一其他此类技术是 Jawin,但我没有任何个人经验:

    2009 年 4 月 26 日更新: 只是为了它,我对 Microsoft Windows Search 进行了更多研究,并找到了一种使用 OLE DB 与其集成的简单方法。这是我编写的一些代码作为概念证明:

    public static void main(String[] args) {
        DispatchPtr connection = null;
        DispatchPtr results = null;
        try {
            Ole32.CoInitialize();
            connection = new DispatchPtr("ADODB.Connection");
            connection.invoke("Open",
                "Provider=Search.CollatorDSO;" +
                "Extended Properties='Application=Windows';");
            results = (DispatchPtr)connection.invoke("Execute",
                "select System.Title, System.Comment, System.ItemName, System.ItemUrl, System.FileExtension, System.ItemDate, System.MimeType " +
                "from SystemIndex " +
                "where contains('Foo')");
            int count = 0;
            while(!((Boolean)results.get("EOF")).booleanValue()) {
                ++ count;
                DispatchPtr fields = (DispatchPtr)results.get("Fields");
                int numFields = ((Integer)fields.get("Count")).intValue();
    
                for (int i = 0; i < numFields; ++ i) {
                    DispatchPtr item =
                        (DispatchPtr)fields.get("Item", new Integer(i));
                    System.out.println(
                        item.get("Name") + ": " + item.get("Value"));
                }
                System.out.println();
                results.invoke("MoveNext");
            }
            System.out.println("\nCount:" + count);
        } catch (COMException e) {
            e.printStackTrace();
        } finally {
            try {
                results.invoke("Close");
            } catch (COMException e) {
                e.printStackTrace();
            }
            try {
                connection.invoke("Close");
            } catch (COMException e) {
                e.printStackTrace();
            }
            try {
                Ole32.CoUninitialize();
            } catch (COMException e) {
                e.printStackTrace();
            }
        }
    }
    

    要编译它,您需要确保 JAWIN JAR 在您的类路径中,并且 jawin.dll 在您的路径中(或 java.library.path 系统属性)。此代码仅打开到本地 Windows 桌面搜索索引的 ADO 连接,使用关键字“Foo”查询文档,并打印出结果文档的一些关键属性。

    如果您有任何问题或需要我澄清任何事情,请告诉我。

    2009 年 4 月 27 日更新: 我也尝试在 JACOB 中实现相同的功能,并将做一些基准测试来比较两者之间的性能差异。我可能在 JACOB 中做错了什么,但它似乎一直在使用 10 倍以上的内存。如果我有时间的话,我也将致力于 jcom 和 com4j 的实现,并尝试找出一些我认为是由于某处缺乏线程安全而导致的怪癖。我什至可以尝试基于 JNI 的解决方案。我希望在 6-8 周内完成所有工作。

    2009 年 4 月 28 日更新: 对于那些一直在关注和好奇的人来说,这只是一个更新。事实证明没有线程问题,我只需要显式关闭我的数据库资源,因为 OLE DB 连接可能是在操作系统级别汇集的(我可能应该已经关闭了连接......)。我认为我不会对此进行任何进一步的更新。如果有人遇到任何问题,请告诉我。

    2009 年 5 月 1 日更新: 根据 Oscar 的要求添加了 JACOB 示例。从 COM 的角度来看,这经历了完全相同的调用序列,只是使用了 JACOB。虽然最近 JACOB 确实得到了更积极的工作,但我也注意到它非常消耗内存(使用的内存是 Jawin 版本的 10 倍)

    public static void main(String[] args) {
        Dispatch connection = null;
        Dispatch results = null;
    
        try {
            connection = new Dispatch("ADODB.Connection");
            Dispatch.call(connection, "Open",
                "Provider=Search.CollatorDSO;Extended Properties='Application=Windows';");
            results = Dispatch.call(connection, "Execute",
                "select System.Title, System.Comment, System.ItemName, System.ItemUrl, System.FileExtension, System.ItemDate, System.MimeType " +
                "from SystemIndex " +
                "where contains('Foo')").toDispatch();
            int count = 0;
            while(!Dispatch.get(results, "EOF").getBoolean()) {
                ++ count;
                Dispatch fields = Dispatch.get(results, "Fields").toDispatch();
                int numFields = Dispatch.get(fields, "Count").getInt();
    
                for (int i = 0; i < numFields; ++ i) {
                    Dispatch item =
                        Dispatch.call(fields, "Item", new Integer(i)).
                        toDispatch();
                    System.out.println(
                        Dispatch.get(item, "Name") + ": " +
                        Dispatch.get(item, "Value"));
                }
                System.out.println();
                Dispatch.call(results, "MoveNext");
            }
        } finally {
            try {
                Dispatch.call(results, "Close");
            } catch (JacobException e) {
                e.printStackTrace();
            }
            try {
                Dispatch.call(connection, "Close");
            } catch (JacobException e) {
                e.printStackTrace();
            }
        }
    }
    

    【讨论】:

    • 我应该补充一下,我不太了解 Windows 编程:-S 我以前看过这个库,但是因为我不确定下一步该做什么,所以没有进一步了解?您可以在 MSDN 文档上进行示例搜索以使用 jacob 吗?
    • 这很有趣!我是一个正在学习计算机科学的新手,我想知道在哪里可以了解更多关于“进入”窗口的信息,并从 java 或任何其他语言中做类似的事情。书籍或网页的任何标题?我已经在 msdn 上阅读了几天,但它不适合初学者.. :)
    • 我什么都不知道,我只是快速浏览了 Jawin 文档,然后是 Microsoft 提供的 COM 组件 API 参考。这是一个开始,但我怀疑如果我尝试更复杂的事情会遇到更多问题。
    • 效果很好。现在我正在尝试基于此获得更多列:bit.ly/Rbeu8 我想知道 JNA、JACOB 和 JAWIN 等是否过时了。大多数变化都有几年的历史。我即将将此标记为已接受。你碰巧有一个 JACOB 样本吗 :P :) –
    • 如何更改类路径和路径?它会影响我的整个“java系统”还是只是当前项目..?
    【解决方案2】:

    这里很少有帖子建议您可以使用 JACOB、JNBridge、J-Integra 等商业或免费框架在 Java 和 .NET 或 COM 之间架起一座桥梁。 实际上,我曾与这些第三方之一(一个昂贵的 :-) 有过合作经验,我必须说我会尽我所能避免将来重复这个错误。原因是它涉及到很多你无法真正调试的“巫毒”东西,当出现问题时要理解问题是什么非常复杂。

    我建议您实施的解决方案是创建一个简单的 .NET 应用程序,该应用程序对 Windows 搜索 API 进行实际调用。这样做之后,您需要在该组件和您的 Java 代码之间建立一个通信通道。这可以通过多种方式完成,例如通过向应用程序定期提取的小型数据库发送消息。或者在机器 IIS(如果存在)上注册此组件并公开简单的 WS API 以与之通信。

    我知道这可能听起来很麻烦,但明显的优势是:a) 您可以使用 Windows 搜索 API 所理解的语言(.NET 或 COM)与它进行通信,b) 您可以控制所有应用程序路径。

    【讨论】:

    • 我实际上已经考虑了第二个选项,使用 ws。我知道一些可以使用的轻量级 Java 框架/网络服务器,我不知道是否有其他东西可以用于相同的目的。 IIS 是一个完整的未来网络服务器,而只需要一个基本的 http 通信。
    • 有很多轻量级 Java 服务器,但如果我理解您的问题,您需要 .NET 代码(不是 Java)才能在 Web 服务器上运行,因此 IIS 将是第一个也是最简单的选择
    • 嘿 Lior,如果这更复杂,我倾向于同意你的观点,但我认为这很简单(只是一个 OLE DB 调用),因此我认为是 Java/COM 调用应该不是问题。不过,我一直在阅读这方面的内容,看起来 Java-COM 集成可能是一场噩梦,尤其是当线程开始发挥作用时(例如,多个 Java 线程共享一个 COM 对象)。
    • 嘿,Jack,你是对的,毕竟我们有一个使用这些桥接技术之一正式发布的产品,它仍然有效。但是一路上我们遇到了很多问题。当您无法“控制”您的代码时,这只是一种令人沮丧的感觉。无论如何,我试图提出一个替代方案,而不是取消你的答案。
    【解决方案3】:

    您为什么不能只使用Runtime.exec() 来通过search-ms 查询并读取带有命令结果的BufferedReader?例如:

    public class ExecTest {
        public static void main(String[] args) throws IOException {
            Process result = Runtime.getRuntime().exec("search-ms:query=microsoft&");
    
            BufferedReader output = new BufferedReader(new InputStreamReader(result.getInputStream()));
            StringBuffer outputSB = new StringBuffer(40000);
            String s = null;
    
            while ((s = output.readLine()) != null) {
                outputSB.append(s + "\n");
                System.out.println(s);
            }
    
            String result = output.toString();
        }
    }
    

    【讨论】:

    • 阅读第二行。我设法做的是调用 Windows 资源管理器来显示结果。不完全是我需要的(在第 2 行阅读结束)。或者,我在这里遗漏了什么?
    • 啊,你是对的。我不熟悉 Windows Search 并且在 Mac 上运行,所以我没有意识到它会调用资源管理器。很抱歉!
    • 没问题。无论如何感谢您的帮助。顺便说一句,要使您的帖子运行,它应该如下所示:pastebin.com/fa34637e
    【解决方案4】:

    有几个库用于从 java 调用 COM 对象,一些是开源的(但它们的学习曲线更高)一些是封闭源代码并且具有更快的学习曲线。一个封闭源代码示例是EZCom。商业的也倾向于专注于从 Windows 调用 java,这是我在开源中从未见过的。

    在你的情况下,我建议你做的是在你自己的 .NET 类中调用前面(我想使用 C#,因为它最接近 Java,而不涉及有争议的 J#),并专注于与.NET DLL。这样windows编程就更简单了,windows和java的接口也更简单了。

    如果您正在寻找如何使用 java com 库,MSDN 是错误的地方。但是 MSDN 将帮助您在 .NET 中编写所需的内容,然后查看 com 库教程,了解如何从 .NET 对象中调用您需要的一两个方法。

    编辑:

    鉴于答案中有关使用 Web 服务的讨论,您可以(并且可能会有更好的运气)构建一个调用嵌入式 Java Web 服务器的小型 .NET 应用程序,而不是尝试让 .NET 具有嵌入式 Web 服务,并让 java 成为调用的消费者。对于嵌入式 Web 服务器,我的研究表明 Winstone 很好。不是最小的,但更灵活。

    让它工作的方法是从 java 启动 .NET 应用程序,并让 .NET 应用程序在计时器或循环上调用 Web 服务以查看是否有请求,如果有,则处理它并发送响应。

    【讨论】:

    • 不完全是在寻找 java/com 库(至少这不是问题的基本原理),而是从 Java 中使用 windows 搜索。 (尽管我在 java/com lib 方向上得到了几个答案)
    • 使用 Windows 搜索的唯一方法是使用 Windows API,因此从 java 与 Windows API 交互的唯一方法是 COM、DCOM 或 CORBA 或某种套接字层(如网络服务)。这就是为什么我们都将您指向 java/com 网桥的原因。
    猜你喜欢
    • 2023-01-12
    • 2010-09-06
    • 1970-01-01
    • 2021-03-19
    • 1970-01-01
    • 2013-09-22
    • 2013-01-30
    • 2015-02-20
    • 2017-07-31
    相关资源
    最近更新 更多