从 FileReader 更改为 getResourceAsStream
Changing from FileReader to getResourceAsStream
当我尝试从 .jar 文件加载我的小游戏时,fileReader 将不再工作,我被建议改用 getResourceAsStream 函数,当我 运行 下面的代码时IDE 它工作正常所以路径是正确的,当我更改为当前被注释掉的 getResourceAsStream 并删除文件 reader 行时,我得到这些错误。
Exception in thread "Thread-0" java.lang.NullPointerException
at java.io.Reader.<init>(Reader.java:78)
at java.io.InputStreamReader.<init>(InputStreamReader.java:72)
有什么办法可以解决这个问题吗?
public class Utils {
public static String loadFileAsString(String path) {
StringBuilder builder = new StringBuilder();
try{
//InputStream is = Utils.class.getResourceAsStream(path);
//BufferedReader br = new BufferedReader(new InputStreamReader(is));
BufferedReader br = new BufferedReader(new FileReader(path));
String line;
while((line = br.readLine()) != null)
builder.append(line + "\n");
br.close();
}catch(IOException e){
e.printStackTrace();
}
return builder.toString();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/res" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="file://$MODULE_DIR$/res" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library" exported="">
<library>
<CLASSES>
<root url="file://$MODULE_DIR$/res/worlds" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
</component>
</module>
您需要开始了解自己在做什么,class路径是什么,Java 如何加载 classes,以及应用程序是如何捆绑的。
当您启动 Java 程序时,您使用如下命令:
java -cp /some/directory:/some/file.jar com.foo.bar.Main
根据上述命令,java 将尝试在两个位置加载主 class(以及代码中使用的所有其他 classes):
/some/directory
目录
- jar 文件
/some/file.jar
由于 class 名为 Main,并且在包 com.foo.bar 中,因此它将查找名为 /some/directory/com/foo/bar/Main.class
的文件,如果找不到,则它将在 jar 文件中查找条目 /com/foo/bar/Main.class
.
当您使用 SomeClass.getResourceAsStream("/res/worlds/world1.txt")
时,它将应用相同的策略:查找文件 /some/directory/res/worlds/world1.txt
,如果未找到,则在 jar 文件中查找条目 /res/worlds/world1.txt
。
因此,由于您使用 IDE 到 运行 项目,您需要了解 IDE 的工作原理:它使用什么命令来启动您的程序。原理很简单:
- 有一个目标目录,IDE 放置它从源 .java 文件生成的 .class 文件。当 运行 为 IDE
设置程序时,此目标目录是 class 路径的一部分
- 还有一个目标目录,其中 IDE 存储所有不是 .java 文件的文件,并且位于 IntelliJ 中标记为 "Resources root" 的目录下。此目标目录也是 class 路径的一部分。
目标目录中的结构始终遵循 source/resource 目录的结构。
将应用程序打包为 jar 文件时,您最终会得到一个包含这些目标目录下所有内容的 jar 文件。
默认情况下,在基本的 IntelliJ 项目中,您的 src 目录也是资源根目录。所以你放在那里的每个文件最终都在目标目录中,因此在 class 路径中可用,无论是从 IDE 启动时,还是当目标目录被打包为 jar 时。你应该把文件放在 src 目录下的某个地方,不要弄乱依赖关系。您的 txt 文件是项目源代码的一部分,就像 Java 文件一样。 IDE 将其与 .class 文件一起复制到目录中,从而成为 "compiled"。
Exception in thread "Thread-0" java.lang.NullPointerException
at java.io.Reader.<init>(Reader.java:78)
at java.io.InputStreamReader.<init>(InputStreamReader.java:72)
有什么办法可以解决这个问题吗?
public class Utils {
public static String loadFileAsString(String path) {
StringBuilder builder = new StringBuilder();
try{
//InputStream is = Utils.class.getResourceAsStream(path);
//BufferedReader br = new BufferedReader(new InputStreamReader(is));
BufferedReader br = new BufferedReader(new FileReader(path));
String line;
while((line = br.readLine()) != null)
builder.append(line + "\n");
br.close();
}catch(IOException e){
e.printStackTrace();
}
return builder.toString();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/res" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="file://$MODULE_DIR$/res" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="module-library" exported="">
<library>
<CLASSES>
<root url="file://$MODULE_DIR$/res/worlds" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
</component>
</module>
您需要开始了解自己在做什么,class路径是什么,Java 如何加载 classes,以及应用程序是如何捆绑的。
当您启动 Java 程序时,您使用如下命令:
java -cp /some/directory:/some/file.jar com.foo.bar.Main
根据上述命令,java 将尝试在两个位置加载主 class(以及代码中使用的所有其他 classes):
/some/directory
目录- jar 文件
/some/file.jar
由于 class 名为 Main,并且在包 com.foo.bar 中,因此它将查找名为 /some/directory/com/foo/bar/Main.class
的文件,如果找不到,则它将在 jar 文件中查找条目 /com/foo/bar/Main.class
.
当您使用 SomeClass.getResourceAsStream("/res/worlds/world1.txt")
时,它将应用相同的策略:查找文件 /some/directory/res/worlds/world1.txt
,如果未找到,则在 jar 文件中查找条目 /res/worlds/world1.txt
。
因此,由于您使用 IDE 到 运行 项目,您需要了解 IDE 的工作原理:它使用什么命令来启动您的程序。原理很简单:
- 有一个目标目录,IDE 放置它从源 .java 文件生成的 .class 文件。当 运行 为 IDE 设置程序时,此目标目录是 class 路径的一部分
- 还有一个目标目录,其中 IDE 存储所有不是 .java 文件的文件,并且位于 IntelliJ 中标记为 "Resources root" 的目录下。此目标目录也是 class 路径的一部分。
目标目录中的结构始终遵循 source/resource 目录的结构。
将应用程序打包为 jar 文件时,您最终会得到一个包含这些目标目录下所有内容的 jar 文件。
默认情况下,在基本的 IntelliJ 项目中,您的 src 目录也是资源根目录。所以你放在那里的每个文件最终都在目标目录中,因此在 class 路径中可用,无论是从 IDE 启动时,还是当目标目录被打包为 jar 时。你应该把文件放在 src 目录下的某个地方,不要弄乱依赖关系。您的 txt 文件是项目源代码的一部分,就像 Java 文件一样。 IDE 将其与 .class 文件一起复制到目录中,从而成为 "compiled"。