无法在所有计算机上的JAR中访问资源 [英] Can't access resource in a JAR on all computers

查看:90
本文介绍了无法在所有计算机上的JAR中访问资源的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个应用程序(特别是Bukkit Minecraft服务器的插件)。这样做需要我从应用程序的JAR中访问一个.properties文件。这是我遇到一个奇怪的问题。当我在开发PC上测试程序时,它运行得很好。 .properties文件被加载,一切都很好。然而,在我测试的另一台计算机上,我尝试启动该应用程序,并且无法加载属性,并且 InputStream 。这里是我加载文件的方法:

  public class Points {
private HashMap< String,MessageFormat>消息;

public Points(){
buildMessages();


public static void buildMessages(){
属性messageProps = new Properties();
InputStream in = Points.class.getResourceAsStream(resources / messages.properties);
messages = new HashMap< String,MessageFormat>();
Enumeration en;
尝试{
messageProps.load(in);
} catch(IOException ex){
System.err.println(Could not read message properties file!);
return;
} catch(NullPointerException ex){
System.err.println(Could not read message properties file!);
if(in == null)
System.out.println(IOStream null);
return;
}
en = messageProps.propertyNames();
while(en.hasMoreElements()){
String key =(String)en.nextElement();
String prop = messageProps.getProperty(key);
MessageFormat form = new MessageFormat(prop.replaceAll(&,
\\\§)。replaceAll(`,));
messages.put(key,form);





$ b

我省略了一些不相关的代码,但这是它的主旨。 JAR的结构如下:

$ $ p $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ b Points.java< - 加载文件的类
resources /
messages.properties< - 正在加载的文件

在我的电脑上,文件从 resources / messages.properties 加载,但是在另一个文件中, code> InputStream 为null,并且 NullPointerException 的我的 catch 块为跑。什么可能导致这个问题,我怎么能解决它?更新:即使使用完整路径( /com/pvminecraft/points/resources/messages.properties ),同样的问题仍然存在。



更新2:以下是完整的堆栈跟踪: / p>

  java.lang.NullPointerException $ b $ java.util.Properties $ LineReader.readLine(Properties.java:435)$在java.util.Properties.load0处使用b $ b(Properties.java:354)在java.util.Properties.load处使用
(Properties.java:342)在com.pvminecraft.points.Points处使用
。 buildMessages(Unknown Source)
at com.pvminecraft.points.Points.onEnable(Unknown Source)
at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:188)
在org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:968)
在org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:280)
在org.bukkit.craftbukkit .CraftServer.loadPlugin(CraftServer.java:186)
a吨org.bukkit.craftbukkit.CraftServer.enablePlugins(CraftServer.java:169)
。在org.bukkit.craftbukkit.CraftServer.reload(CraftServer.java:436)
。在org.bukkit.Bukkit.reload (Bukkit.java:187)在org.bukkit.command.defaults.ReloadCommand.execute(ReloadCommand.java:22)

在org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:165 )
在org.bukkit.craftbukkit.CraftServer.dispatchCommand(CraftServer.java:378)
处净org.bukkit.craftbukkit.CraftServer.dispatchCommand(CraftServer.java:374)
。 minecraft.server.MinecraftServer.b(MinecraftServer.java:564)
在net.minecraft.server.MinecraftServer.w(MinecraftServer.java:541)
在net.minecraft.server.MinecraftServer.run( MinecraftServer.java:425)
at net.minecraft.server.ThreadServerApplication.run(SourceFile:457)

所有的 org.bukkit org.craftbukkit stuff是服务器。 .properties文件被加载到 buildMessages 方法中,由 onEnable 方法调用



更新3 :在全新安装的Arch Linux上,正确加载消息属性文件,很好。远程服务器是Ubuntu Linux,我的开发电脑是Arch。



更新4:好的,这是一个解决方案。这似乎是一个本地化的问题。我说,因为我已经设法访问了两台以上的电脑,而且这两个程序都能正常运行。虽然这很烦人,但我的代码或构建脚本似乎没有任何问题。我仍然想知道什么是错的,但是现在不再紧迫。我会继续研究这个。感谢大家。

解决方案

Point.class.getClassLoader()。getResourceAsStream(com / pvminecraft / points /resources/messages.properties);



在没有第一个/的情况下尝试它,它应该在运行JVM的任何地方工作。 p>

如果这样做不起作用,请尝试将该文件放入JAR文件的ROOT中,然后重试。



如果仍然不起作用,请尝试使用此方法:

  public static byte [] getFile(File zip,String fileName)抛出FileNotFoundException,ZipException,IOException {
字符串文件名=文件名;

if(!zip.exists()){
throw new FileNotFoundException(zip.getName());

while(filename.charAt(0)=='/'|| filename.charAt(0)=='\\'){
filename = filename.substring( 1);


if(filename.contains(\\)){
filename = filename.replace(\\,/);
}

ZipFile zipFile = new ZipFile(zip);
枚举条目= zipFile.entries();

ByteArrayOutputStream输出;
byte [] result = null;

while(entries.hasMoreElements()){
ZipEntry entry =(ZipEntry)entries.nextElement(); ();}

if(entry.getName()。equalsIgnoreCase(filename)){
FileUtils.copyInputStream(zipFile.getInputStream(entry),output = new ByteArrayOutputStream());
result = output.toByteArray();
zipFile.close();
output.close();
返回结果;
}
}

zipFile.close();
抛出新的FileNotFoundException(filename);

$ / code>

您需要这个

  public static void copyInputStream(InputStream in,OutputStream out)throws IOException {
byte [] buffer = new byte [1024];
int len; (((len = in.read(buffer))> = 0)){
out.write(buffer,0,len);
}
out.flush();

$ / code>

获取正在运行的jar的路径

  String currentJar =; 
//获取当前的jar路径。由于用户可以重命名这个文件,我们需要这样做
try {
currentJar =(Points.class.getProtectionDomain()。getCodeSource()。getLocation()。toURI()。getPath()) ;
if(currentJar.startsWith(/))currentJar = currentJar.substring(1);
} catch(URISyntaxException ex){
}

第一个'/'

最后调用方法: getFile(currentJar, PATH_TO_PROPERTIES_FILE);



您将拥有一组可用的字节。只要把它作为一个ByteArrayInputStream和你的问题应该被解决。




该代码是一个util类的一部分我已经创建,这就是为什么不必要的读到一个字节数组,但ofc,你可以改变它直接使用InputStream到Properties.load()方法。



链接ZIP工具类



http://all-inhonmodman.svn.sourceforge.net/viewvc/all-inhonmodman/ModManager/src/modmanager/实用程序/ ZIP.java?revision = 292& content-type = text%2Fplain



FileUtils util类的链接

http://all-inhonmodman.svn.sourceforge.net/viewvc /all-inhonmodman/ModManager/src/modmanager/utility/FileUtils.java?revision=294&content-type=text%2Fplain


I'm writing an application (specifically a plugin for the Bukkit Minecraft server). Doing this requires that I access a .properties file from the JAR of the application. This is where I encounter a strange problem. When I test the program on my development PC, it runs just fine. The .properties file gets loaded and everything is fine. However, on the other computer that I test it on, I try to start the app, and it can't loaded the properties, and the InputStream is null. Here is the method in which I load the file:

public class Points {
    private HashMap<String, MessageFormat> messages;

    public Points() {
         buildMessages();
    }

public static void buildMessages() {
        Properties messageProps = new Properties();
        InputStream in = Points.class.getResourceAsStream("resources/messages.properties");
        messages = new HashMap<String, MessageFormat>();
        Enumeration en;
        try {
            messageProps.load(in);
        } catch(IOException ex) {
            System.err.println("Couldn't read message properties file!");
            return;
        } catch(NullPointerException ex) {
            System.err.println("Couldn't read message properties file!");
            if(in == null)
                System.out.println("IOStream null");
            return;
        }
        en = messageProps.propertyNames();
        while(en.hasMoreElements()) {
            String key = (String)en.nextElement();
            String prop = messageProps.getProperty(key);
            MessageFormat form = new MessageFormat(prop.replaceAll("&", 
                "\u00a7").replaceAll("`", ""));
            messages.put(key, form);
        }
    }
}

I've omitted some irrelevant code, but that is the gist of it. The structure of the JAR is as follows:

   com/
       pvminecraft/
           points/
               Points.java <-- The class where the file is loaded
               resources/
                   messages.properties <-- The file being loaded

On my PC the file is loaded from resources/messages.properties, but on the other file, the InputStream is null, and my catch block for the NullPointerException is run. What could be causing the problem, and how could I fix it? Thanks.

Update: Even using the full path (/com/pvminecraft/points/resources/messages.properties), the same issue is still persistent.

Update 2: Here is the full stack-trace:

java.lang.NullPointerException
    at java.util.Properties$LineReader.readLine(Properties.java:435)
    at java.util.Properties.load0(Properties.java:354)
    at java.util.Properties.load(Properties.java:342)
    at com.pvminecraft.points.Points.buildMessages(Unknown Source)
    at com.pvminecraft.points.Points.onEnable(Unknown Source)
    at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:188)
    at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:968)
    at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:280)
    at org.bukkit.craftbukkit.CraftServer.loadPlugin(CraftServer.java:186)
    at org.bukkit.craftbukkit.CraftServer.enablePlugins(CraftServer.java:169)
    at org.bukkit.craftbukkit.CraftServer.reload(CraftServer.java:436)
    at org.bukkit.Bukkit.reload(Bukkit.java:187)
    at org.bukkit.command.defaults.ReloadCommand.execute(ReloadCommand.java:22)
    at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:165)
    at org.bukkit.craftbukkit.CraftServer.dispatchCommand(CraftServer.java:378)
    at org.bukkit.craftbukkit.CraftServer.dispatchCommand(CraftServer.java:374)
    at net.minecraft.server.MinecraftServer.b(MinecraftServer.java:564)
    at net.minecraft.server.MinecraftServer.w(MinecraftServer.java:541)
    at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:425)
    at net.minecraft.server.ThreadServerApplication.run(SourceFile:457)

All of the org.bukkit and org.craftbukkit stuff is the server. The .properties file is loaded in the buildMessages method, called by the onEnable method of Points.

Update 3: On a fresh install of Arch Linux, the message properties file is loaded correctly and all is well. The remote server is Ubuntu Linux, and my dev PC is Arch.

Update 4: Alright, this is sort of a resolution. It seems to be a localized problem. I say that because I've managed to get access to two more computers, and the program runs correctly on both. While it's annoying, this doesn't seem to be anything wrong with my code or build scripts. I'm still wanting to know what's wrong, but it isn't pressing any more. I'll continue looking into this. Thanks everyone.

解决方案

Point.class.getClassLoader().getResourceAsStream("com/pvminecraft/points/resources/messages.properties");

Try it without the first '/' and it should work anywhere running a JVM.

If that didn't work, please try to put the file in the ROOT of the JAR file and try it again.

If still doesn't work, try using this method:

public static byte[] getFile(File zip, String fileName) throws FileNotFoundException, ZipException, IOException {
        String filename = fileName;

        if (!zip.exists()) {
            throw new FileNotFoundException(zip.getName());
        }
        while (filename.charAt(0) == '/' || filename.charAt(0) == '\\') {
            filename = filename.substring(1);
        }

        if (filename.contains("\\")) {
            filename = filename.replace("\\", "/");
        }

        ZipFile zipFile = new ZipFile(zip);
        Enumeration entries = zipFile.entries();

        ByteArrayOutputStream output;
        byte[] result = null;

        while (entries.hasMoreElements()) {
            ZipEntry entry = (ZipEntry) entries.nextElement();

            if (entry.getName().equalsIgnoreCase(filename)) {
                FileUtils.copyInputStream(zipFile.getInputStream(entry), output = new ByteArrayOutputStream());
                result = output.toByteArray();
                zipFile.close();
                output.close();
                return result;
            }
        }

        zipFile.close();
        throw new FileNotFoundException(filename);
    }

You will need this

public static void copyInputStream(InputStream in, OutputStream out) throws IOException {
    byte[] buffer = new byte[1024];
    int len;
    while (((len = in.read(buffer)) >= 0)) {
        out.write(buffer, 0, len);
    }
    out.flush();
}

Get the path of the running jar

 String currentJar = "";
                                        // Get current jar path. Since user may rename this file, we need to do this way
              try {
                   currentJar = (Points.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
                   if (currentJar.startsWith("/")) currentJar = currentJar.substring(1);
                   } catch (URISyntaxException ex) {
                   }

The first '/' I don't really remember why it appears, but it do, so you must remove it:

Finally call the method: getFile(currentJar, "PATH_TO_PROPERTIES_FILE");

You will have an array of bytes to work with. Just put it as a ByteArrayInputStream and your problems should be solved.


That code is part of a util class I've created, that's why the unecessary read to a byte array, but ofc, you can change it to use directly that InputStream to the Properties.load() method.

Link for the ZIP util class

http://all-inhonmodman.svn.sourceforge.net/viewvc/all-inhonmodman/ModManager/src/modmanager/utility/ZIP.java?revision=292&content-type=text%2Fplain

Link for the FileUtils util class

http://all-inhonmodman.svn.sourceforge.net/viewvc/all-inhonmodman/ModManager/src/modmanager/utility/FileUtils.java?revision=294&content-type=text%2Fplain

这篇关于无法在所有计算机上的JAR中访问资源的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆