【问题标题】:How do I access a file inside an OSGi bundle?如何访问 OSGi 包中的文件?
【发布时间】:2011-09-22 09:50:41
【问题描述】:

我是 OSGi 的新手,我创建了一个 OSGi 捆绑包,我在 Apache Felix OSGi 容器中运行它。 捆绑包中包含一个文件资源,我需要将其作为java.io.File 传递给一个方法。要实例化文件对象,“文件”方案中的 URI 或字符串形式的路径是必需的。如何以干净的方式检索其中的任何一个?

我尝试使用 context.getBundle().getResource("/myfile")(其中上下文的类型为 org.osgi.framework.BundleContext),它返回 URI bundle://6.0:0/myfile。 但是这个 URI 不能使用 File(URI uri) 构造函数转换为文件实例,因为它有“bundle”-scheme。

可以尝试构建一个知道工作目录并利用我的包的 bundleId 的位置的路径,但我怀疑这是最佳做法。

有什么想法吗?

【问题讨论】:

  • Equinox 具有特殊的实用程序类,可以以面向未来的方式进行此类转换,但我不了解 Felix。如果您想针对干净的 OSGi API 编写代码,则需要将此文件复制到某个位置,以便您可以轻松检索相应的 File 对象(例如在您的 Bundle.getDataFile() 存储中)。

标签: osgi apache-felix file-access


【解决方案1】:

由于文件您的捆绑包中,因此您无法使用标准的File 访问它。从Bundle.getResource() 获得的URL 是获取这些资源的正确方法,因为OSGi API 也适用于没有实际文件系统的系统。我总是会尝试坚持使用 OSGi API,而不是使用特定于框架的解决方案。

因此,如果您可以控制该方法,我会将其更新为采用URL,甚至可能是InputStream(因为您可能只想从中读取)。为方便起见,您始终可以提供一个确实采用File的辅助方法。

如果您无法控制该方法,则必须编写一些辅助方法来获取 URL,将其流式传输到文件中(例如,File.createTempFile() 可能会解决问题。

【讨论】:

  • 感谢您的回答。我无法控制该方法,因为它是我无法修改的依赖项,并且此依赖项指示 File 类型的参数。套用您的答案:您建议通过 InputStream 访问文件并将其作为临时文件写入通过 OSGi-API 引用的包的私有区域中。这是一般的最佳做法吗?因为使用这种技术,物理内存中的资源增加了一倍。假设您有多个文件,它们都会翻倍,这在小型设备上可能是个问题。还是我错过了一点?
  • 你说得对,这是一种低效率,这是由 OSGi(“每个资源都有一个 URL,即使我们没有文件”)和你的库( “我必须有一个文件”)。您可以使用临时文件,或使用您的捆绑存储;最适合您的情况。
  • Angelo 是正确的...您使用的库设计不当。它坚持你给它一个文件,但你所拥有的不是文件,它是文件的片段(技术上,ZIP 的条目)。因此,效率低下是不可避免的。
  • @Namphibian,是的,已修复。
【解决方案2】:

也许 API 容易混淆,但您可以像这样访问 OSGI 包中的文件:

URL url = context.getBundle().getResource("com/my/weager/impl/test.txt");

// The url maybe like this: bundle://2.0:2/com/my/weager/impl/test.txt
// But this url is not a real file path :(, you could't use it as a file.
// This url should be handled by the specific URLHandlersBundleStreamHandler, 
// you can look up details in BundleRevisionImpl.createURL(int port, String path)
System.out.println(url.toString());

BufferedReader br =new BufferedReader(new InputStreamReader(url.openConnection().getInputStream()));
while(br.ready()){
    System.out.println(br.readLine());
}
br.close();

getResource 会像 OSGI 类加载器理论一样通过整个 OSGI 容器查找资源。
getEntry 将从本地包中查找资源。并且返回 url 可以转换为文件但 inputStream.
这是一个与此相同的问题:No access to Bundle Resource/File (OSGi) 希望这对您有所帮助。

【讨论】:

    【解决方案3】:

    我使用的是getClassLoader().getResourceAsStream():

    InputStream inStream = new java.io.BufferedInputStream(this.getClass().getClassLoader().getResourceAsStream(fileName));
    

    这样文件将从您的资源目录加载。 FileName 应该包含“src/main/resources”之后的路径。

    此处为完整示例:

    static public byte[] readFileAsBytes(Class c, String fileName) throws IOException {
        InputStream inStream = new java.io.BufferedInputStream(c.getClassLoader().getResourceAsStream(fileName));
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int nbytes = 0;
        byte[] buffer = new byte[100000];
    
        try {
            while ((nbytes = inStream.read(buffer)) != -1) {
                out.write(buffer, 0, nbytes);
            }
            return out.toByteArray();
        } finally {
            if (inStream != null) { 
                inStream.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-07-22
      • 2011-04-16
      • 2011-10-08
      • 1970-01-01
      • 1970-01-01
      • 2011-05-26
      • 2014-07-24
      • 2011-12-16
      • 2017-06-08
      相关资源
      最近更新 更多