如何在可导出的库中正确设置资源

huangapple go评论74阅读模式
英文:

How to correctly setup resources in a exportable library

问题

在我创建的一个库中,我有以下行来检索我的资源:

private static final File fragment = new File(DefaultShader.class.getClassLoader().getResource("file.txt").getFile());

但是当我将这个库导出为一个JAR文件,并尝试在另一个应用程序中使用它时,当在内部读取相同的行时,我会收到一个I/O错误,因为它试图访问JAR文件。

java.io.FileNotFoundException: file:\C:\Users\me\test\libs\lib.jar!\file.txt

Node.js通过提供返回脚本的运行位置路径的方法使得这更加容易,显然在Java中没有类似的方法,或者我只是找不到。有什么方法可以解决这个问题?

英文:

In a library I made, I have the following line to retrieve my resources:

private static final File fragment = new File(DefaultShader.class.getClassLoader().getResource("file.txt").getFile());

But when I export this library to a JAR and attempt to use it in another application, when this same line is read internally I get an I/O error because it's trying to access the JAR.

java.io.FileNotFoundException: file:\C:\Users\me\test\libs\lib.jar!\file.txt

Nodejs would make this easier by providing methods that returns the runtime location path of a script, apparently there is not an equivalent in Java or just couldn't find it. How can I get around this issue?

答案1

得分: 1

不要调用URL的getFile方法。它不会返回有效的文件名,只会返回URL的路径部分。

嵌入在.jar文件中的资源不是File,您不能将其视为File进行引用。

幸运的是,您不需要File对象。您可以直接使用getResourceAsStream来读取:

DefaultShader.class.getResourceAsStream("/file.txt")

显然,您不应该将InputStream存储在static final字段中。但是,您可以轻松地创建一个方法代替:

private static InputStream readFileData() {
    return DefaultShader.class.getResourceAsStream("/file.txt");
}

请注意,资源应该放在包中,就像类一样。将资源放在.jar的根目录中就像将文件写入驱动器的根目录或用户的主目录:如果任何其他程序选择使用相同的文件名,两个程序的结果都将有问题,至少可以这么说。

类似地,如果您的资源位于.jar的根目录中,并且另一个库恰好也在其自己的.jar的根目录中存储了具有相同名称的资源,将会产生冲突,也许您的资源会根据当前的类路径定义而被getResource*方法加载,也可能不会加载您的资源。(这个问题不适用于Java 9+的模块化程序,但仍然最好将资源放在包中。)

将资源放在使用它的类相同的包中被Java SE认为是一种良好的做法:getResourcegetResourceAsStream方法默认情况下会期望在同一个包中找到它。如果字符串参数不以斜杠开头,这些方法会认为它在同一个包中。

这会在DefaultShader类的相同包中查找file.txt:

DefaultShader.class.getResourceAsStream("file.txt")

而这将在类路径中每个.jar的根目录中查找file.txt:

DefaultShader.class.getResourceAsStream("/file.txt")
英文:

Never call the getFile method of URL. It does not return a valid file name. It only returns the path portion of a URL.

A resource embedded in a .jar file is not a File and you cannot refer to it as a File.

Fortunately, you don’t need a File object. You can read it directly using getResourceAsStream:

DefaultShader.class.getResourceAsStream("/file.txt")

Obviously, you should not store an InputStream in a static final field. But you can easily make a method instead:

private static InputStream readFileData() {
    return DefaultShader.class.getResourceAsStream("/file.txt");
}

Be aware that resources should be placed in packages, just like classes. Placing a resource in the root of a .jar is like writing a file to a drive’s root directory or the user’s home directory: if any other program chooses to use the same filename, the results for both programs will be problematic, to say the least.

Similarly, if your resource is in the root of your .jar, and another library also happens to store a resource with the same name in the root of its own .jar, there will be a conflict, and it may or may not be your resource which gets loaded by the getResource* methods, depending on the current classpath definition. (This concern doesn’t apply to Java 9+ modular programs, but it’s still a good idea to keep resources in packages.)

The practice of putting a resource in the same package as the class that uses it is considered a good practice by Java SE: the getResource and getResourceAsStream methods are designed to expect it in the same package as the class by default. If the string argument does not start with a slash, those methods assume it’s in the same package.

This looks for file.txt in the same package as the DefaultShader class:

DefaultShader.class.getResourceAsStream("file.txt")

Whereas this will look for file.txt in the root of every .jar in the classpath:

DefaultShader.class.getResourceAsStream("/file.txt")

huangapple
  • 本文由 发表于 2020年8月25日 05:13:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/63568776.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定