从Java查询Windows搜索

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

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

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

我认为接受的答案是提供有关如何实现这一目标的有用和明确的信息。

提前致谢。

编辑

在我将此标记为已接受之前,是否有人拥有JACOB样本? 🙂

您可能希望了解一种Java-COM集成技术。 我亲自与JACOB(JAva COm Bridge)合作:

这是相当繁琐的(想想专门用reflection工作),但是为我完成了工作(快速certificate概念,从Java中访问MapPoint)。

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

2009年4月26日更新:为了解决这个问题,我对Microsoft Windows Search做了更多研究,并找到了一种使用OLE DB与它集成的简单方法。 这是我写的一些代码作为概念certificate:

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中实现相同的function,并将做一些基准来比较两者之间的性能差异。 我可能在JACOB中做错了什么,但它似乎一直在使用10倍以上的内存。 如果我有时间的话,我也会在jcom和com4j实现上工作,并试图找出一些我认为是由于某些地方缺乏线程安全性的怪癖。 我甚至可以尝试基于JNI的解决方案。 我希望在6-8周内完成所有工作。

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

更新05/01/2009:根据奥斯卡的要求添加了JACOB示例。 这只是使用JACOB从COM角度进行完全相同的调用序列。 虽然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(); } } } 

这里的post很少提示你可以使用商业或免费框架(如JACOB,JNBridge,J-Integra等)在Java和.NET或COM之间架起桥梁。事实上,我有与这些第三方之一的经验(一个昂贵的:-) )我必须说我会尽力避免将来再犯这个错误。 原因是它涉及许多你无法真正调试的“voodoo”东西,当出现问题时理解问题是非常复杂的。

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

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

您有什么理由不能使用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(); } } 

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

在你的情况下,我建议你做的是在你自己的.NET类中调用调用(我想使用C#,因为它最接近Java而没有进入有争议的J#),并专注于与.NET dll建立互操作性。 这样,Windows编程变得更容易,Windows和Java之间的界面更简单。

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

编辑:

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

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