无法访问Bundle资源/文件(OSGi)

11

目前我正在使用Jetty和Equinox开发基于OSGi的Web应用程序(参见:http://wiki.eclipse.org/Jetty/Tutorial/EclipseRT-Jetty-Starter-Kit)。 到目前为止,一切都很好,但是我无法访问我自己bundle的某些文件/资源。这些文件/资源的位置/路径是“configuration/data/config.csv”和“configuration/data/data.zip”。 我已经测试了一切:

context.getBundleContext().getBundle().getEntry("config.csv");
context.getBundleContext().getBundle().getResource("config.csv");
this.getClass().getClassLoader().getResource("config.csv");
context.getBundleContext().getDataFile("config.csv");

当然还有所有可能的路径变体,例如:"configuration/data/config.csv"、"/configuration/data/config.csv"、"\configuration/data/config.csv"、"/config.csv"。 此外,我已经将文件夹添加到了OSGi类路径中(在MANIFEST.MF文件中):

Bundle-ClassPath: .,
 configuration/data/

生成的URL始终是这样的(或为null): "configuration/CBR-Data/config.csv",当我将其转换为文件对象时变成了"D:\configuration\CBR-Data\config.csv"。

但我真正不理解的是,我的一个数据源的属性文件可以完美地加载:
<properties entry="configuration/dsconfig.properties"/>

有人有什么想法/提示或其他东西吗?我快疯了...


你能否发布获取资源URL的代码以及之后如何使用它的代码?当你使用getEntry()时,应将"configuration/data/config.csv"作为参数传递给getEntry()。生成的URL将具有以下格式:bundleentry://20.fwk1235/resource.txt。它似乎不可能具有你发布的格式。因此,从你的问题中无法清楚地了解到某些情况。 - Danail Nachev
你是对的,我很抱歉。URL configURL = context.getBundleContext().getBundle().getEntry("configuration/data/confid.csv"); 的输出是"bundleentry://6.fwk33311724/configuration/data/config.csv"。我尝试通过以下方式将URL转换为文件:File configFile = new File(configURL.getPath());。路径输出 configFile.getAbsolutePath(); 是:"D:\configuration\data\config.csv"。 - Zitzit
2个回答

14

您已经正确地从 bundle 中检索到资源。我建议您熟悉 getEntry()、getResource() 和 getDataFile() 之间的区别。

因为这些方法会返回正确的 URL,这意味着资源被正确地定位了,问题在于您读取它们的方式。

使用它们的两种方法是:

  1. 直接从 URL 打开 InputStream:

    URL configURL = context.getBundleContext().getBundle().getEntry("configuration/data/config.csv");
    if (configURL != null) {
        InputStream input = configUrl.openStream();
        try {
            // process your input here or in separate method
        } finally {
            input.close();
        }
    }
   
  1. URL转换为File。不推荐此方法,因为它假设Bundle部署为目录(而不是存档)。但如果您必须处理需要使用File对象的旧库,则此方法很有帮助。要转换为File,不能使用URL.getPath()方法,因为Equinox具有其自己的URL格式。您应该使用org.eclipse.core.runtime.FileLocator类来解析到FileFileLocator.getBundleFile(Bundle)正好可以完成您想要的功能。

好的,谢谢!关于这个问题有一些疑问:“我建议熟悉getEntry()、getResource()和getDataFile()之间的区别”,你有一些链接/指南/教程可以描述这些差异吗?此外,是否有可能自动将一些目录(例如“configuration/data/”)推送到osgi-configuration目录中,就像对于“org.eclipse.osgi”(“configuration/org.eclipse.osgi/bundles/XX”)所做的那样?-->类似于“configuration/org.mybundle/data/config.csv”。 - Zitzit
@Zitzit - 我不知道有任何这样的指南,我主要依赖于OSGi API javadoc(http://www.osgi.org/javadoc/r4v43/),其中详细解释了每个方法的作用。你为什么想要将一些目录推送到osgi-configuration目录下(我假设这是Equinox配置/文件夹)? 这个文件夹是特定于Equinox的,因此应该限制其使用,否则你会变得依赖Equinox。 - Danail Nachev

4
解决了!!!感谢Danail Nachev(见评论)指引我正确的方向!在搜索“bundleentry://xyz”和“bundleresource://”后,我找到了这个邮件列表帖子:http://www.mail-archive.com/felix-dev@incubator.apache.org/msg02410.html 因此,答案如下(使用(Equinox)FileLocator):
URL configURL = context.getBundleContext().getBundle().getResource("config.csv");
File configFile = new File(FileLocator.toFileURL(configURL).getPath());

但是(也在那个邮件列表中提出了这个问题),如果存在其他解决方案,不仅适用于Equinox,那将会很有意思?


最好您能给Danail Nachev的答案点个赞。另外,与其在问题下添加另一个回答来说明解决方案,不如编辑您原始的问题,在问题下方添加解决方案。 - jfenwick
这是一个很好的例子,说明如何修改你的问题,以便更容易地找到解决方案。http://stackoverflow.com/questions/4538898/map-with-string-is-brokensolved - jfenwick
@jfenwick - 我想知道你为什么这样认为。http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/ 明确表示自己回答问题是正确的做法。 - James Moore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接