执行 java.io.File 或 FileInputStream 时如何引用 OSGi 包中包含的文件

Posted

技术标签:

【中文标题】执行 java.io.File 或 FileInputStream 时如何引用 OSGi 包中包含的文件【英文标题】:How to reference an included file in OSGi bundle when performing java.io.File or FileInputStream 【发布时间】:2011-04-18 03:22:33 【问题描述】:

我正在使用 aQute Bnd 工具集来创建一个 OSGi 包,并与一些依赖的“资源”文件打包在一起。这包括我创建的资源目录中的 *.css 文件和 *.xsd 文件。

我在 bundle.bnd 文件中包含以下内容:

Include-Resource: resources/=resources/ 

当我进行构建时,生成的 *.jar 文件在 jar 包文件的顶层目录的资源目录中具有 *.css 和 *.xsd 文件。

但是,在实际代码中,我很难将其引用为我的类路径的一部分:

我尝试了以下方法:

new File("resources/example.css");

我也试过了:

URL cssFile = this.getClass().getResource("resources/example.css");
try

   file = new File(cssFile.toURI()));

catch(Exception e)

   e.printStackTrace();  

我得到一个 NullPointException 错误或一个 File cannot be found IOException 错误(取决于我使用哪一个)。在调试配置模式下的 Eclipse Equinox 和 Apache Felix(我们用于部署)中运行时出现此错误。注意我试图在 BundleActivator 之外的 Java 类中执行此操作。

我是否需要始终引用 BundleActivator 的上下文,例如?

 /*
 * (non-Javadoc)
 * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
 */
 @Override
 public void start(BundleContext context) throws Exception 
    
     /* Service to host the Bundle interface. */
     ServletContainerService service = new ServletContainerService();
     service.addServlet(new ServletContainer(new AxisServlet(), true));
     this.serverReg = context.registerService(ServletContainerService.class.getName(), service, null);

     cssFile = new File(context.getClass.getResource("resource/example.css")); 
 

我认为上述方法可行,但意味着我将不得不传递似乎不优雅的 cssFile 引用。

是否有任何方法可以引用包含在 bundle/.jar 文件中的任何给定 Java 类中的 bundle jar 文件中的“resources”目录的路径?如果涉及到BundleContext,有没有办法在任何Java类中引用它?

任何帮助将不胜感激。


我已经查看了 Including additional resources with OSGi bundles,但您似乎需要 BundleContext。

我可能已经找到了一个可能的解决方案:http://www.vogella.de/blog/tag/plugin/

看起来 Vogella 有一些示例代码:

URL url;
try 
        url = new URL("platform:/plugin/de.vogella.rcp.plugin.filereader/files/test.txt");
    InputStream inputStream = url.openConnection().getInputStream();
    BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
    String inputLine;

    while ((inputLine = in.readLine()) != null) 
        System.out.println(inputLine);
    

    in.close();

 catch (IOException e) 
    e.printStackTrace();

如果它不是插件并且我使用不同的 OSGi 环境(例如),是否有人知道此路径是否相同。 Equinox Eclipse 与 Apache Felix? 例如url = new URL("platform:/plugin/de.vogella.rcp.plugin.filereader/files/test.txt");

【问题讨论】:

【参考方案1】:

Bundle interface 有一个 getEntry(java.lang.String path) 方法,该方法返回一个 Url,并记录为:

返回此包中指定路径的条目的 URL。这个包的类加载器不用于搜索条目。仅在此捆绑包的内容中搜索条目。 指定的路径总是相对于这个包的根目录,并且可能以“/”开头。路径值“/”表示这个包的根。

【讨论】:

有没有办法在 BundleActivator 的上下文之外访问它?我猜你指的是做这样的事情: public void start(BundleContext context) Bundle bundle = context.getBundle(); InputStream in = bundle.getEntry("/resource/example.css").openStream(); 。但是,我正在寻找一种解决方案(如果有的话)在 BundleActivator 之外访问它。我看了eclipsezone.com/eclipse/forums/t101557.html,但还是很困惑 您是否正在寻找一种从捆绑包 id 获取捆绑对象的方法? 我可以得到条目,但问题是 getEntry() 只提供相对路径,而不是包的完整(根)路径:techinfopad.com/spring/…。【参考方案2】:

我认为答案应该很简单:

URL cssFile = this.getClass().getResource("/resources/example.css");

即确保路径中有一个前导斜杠。你有它没有前导斜杠,这将使它与你调用的类“相对”。

或者以下应该可以工作:

this.getClass().getClassLoader().getResource("resources/example.css");

【讨论】:

我选择了这个解决方案,但在尝试导入所有目录的值时遇到了问题,例如我正在使用 BluePrint CSS 并且 this.getClass().getClassLoader().getResource("resources/css") 有问题,因为不仅有很多文件,还有子目录。我最终将文件“复制”到了一个临时位置,但这会导致一些性能问题。【参考方案3】:

如果您使用 Eclipse/Equinox 进行构建,那么您可以通过调用以下内容从 BundleActivator 中包含的 BundleContext 中获取 Bundle 的位置:

Bundle yourBundle = Platform.getBundle("bundleSymbolicName");
Path relativePathToBundle = new Path("/relativePath");
FileLocator.openStream(yourBundle, relativePathToBundle, false); 

Platform 和 FileLocator 类来自 org.eclipse.core.runtime 插件,因此如果您对它有依赖关系,那么上述内容应该允许您访问您的资源。

【讨论】:

我试图避免使用 org.eclipse.core.runtime 插件,因为我们的部署决定使用 Apache Felix(除非有办法合并它)。如果我在 Eclipse 运行时环境下运行,上述方法有效。

以上是关于执行 java.io.File 或 FileInputStream 时如何引用 OSGi 包中包含的文件的主要内容,如果未能解决你的问题,请参考以下文章

File java IO

IO流一

java io包File类

java.io.File类

IO流:File类的使用

利用java.io.File类实现遍历本地磁盘上指定盘符或文件夹的所有的文件