如何访问OSGi包中的文件?

如何访问OSGi包中的文件?,osgi,apache-felix,file-access,Osgi,Apache Felix,File Access,我是OSGi新手,创建了一个OSGi包,我在ApacheFelixOSGi容器中运行它。 捆绑包中包含一个文件资源,我需要将其作为java.io.file传递给一个方法。要实例化文件对象,需要“文件”方案中的URI或路径作为字符串。我如何以干净的方式检索其中的任何一个 我试着用 context.getBundle().getResource(“/myfile”)(其中context的类型为org.osgi.framework.BundleContext),返回URIbundle://6.0:0/

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

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

我们可以尝试构造一条到该位置的路径,知道工作目录并利用我的bundle的bundleId,但我怀疑这是最佳实践

有什么想法吗

由于文件在您的包中,因此您无法使用标准的
文件来访问它。您从中获取的
URL
是获取这些资源的正确方法,因为OSGiAPI也适用于没有实际文件系统的系统。我会一直坚持OSGiAPI,而不是使用特定于框架的解决方案

因此,如果您可以控制该方法,我会将其更新为使用
URL
,或者甚至是
InputStream
(因为您可能只想从中读取)。为方便起见,您始终可以提供一个助手方法,该方法接受
文件


如果您无法控制该方法,则必须编写一些助手方法,该方法接受
URL
,将其流式输出到一个文件(例如,可能会执行此操作。

可能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。
这里有一个与此相同的问题:
希望这对您有所帮助。

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

这样,文件将从资源目录加载。文件名应包含“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();
        }
    }
}

Equinox有一个特殊的实用程序类,可以以未来的方式进行此类转换,但我不知道Felix。如果您想针对干净的OSGi API编码,您需要将此文件复制到某个地方,在那里您可以轻松检索相应的文件对象(例如在Bundle.getDataFile()存储中)。感谢您的回答。我无法控制该方法,因为它是一个依赖项,我无法修改,并且该依赖项指定了一个File类型的参数。要解释您的答案,您建议通过InputStream访问该文件,并将其作为临时文件写入通过OSGi API引用的捆绑包的私有区域。这是最佳做法吗一般来说,ce?因为使用这种技术,物理内存中的资源会翻倍。假设你有多个文件,它们都会翻倍,这在小型设备上可能是个问题。或者我遗漏了一点?你完全正确,这是一种低效率,是由OSGi和OSGi在理念上的差异造成的(“每个资源都有一个URL,即使我们没有文件)和你的库(“我必须有一个文件”)。你可以使用临时文件,或使用捆绑存储;任何最适合你的情况。Angelo是正确的……你使用的库设计得很糟糕。它坚持你给它一个文件,但你拥有的不是文件,而是文件的一部分。”(从技术上讲,是一个拉链的入口)。因此效率低下是不可避免的。@Namphibian,是的,修复了它。
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();
        }
    }
}