[英]Exported JAR unable to read local file
My Java application has a local file called "classes" (a simple List<String>
) in a top-level folder called "assets". 我的Java应用程序在名为“ assets”的顶级文件夹中有一个名为“ classes”(简单的
List<String>
)的本地文件。 When I run the code below from Eclipse, the file is read no problem. 当我从Eclipse运行以下代码时,读取文件没有问题。
try { // read in classes from local file
ObjectInputStream inputStream =
new ObjectInputStream(new FileInputStream("assets\\classes".replace("\\", "/")));
listOfClasses = (List<String>) inputStream.readObject();
System.out.println("*** Reading local copy of classes file ***");
inputStream.close();
} catch (FileNotFoundException e) { e.printStackTrace();
} catch (ClassNotFoundException e) { e.printStackTrace();
} catch (IOException e) { e.printStackTrace(); }
When I export my application as a JAR, and run it on a different computer, I get a java.io.FileNotFoundException
on the 3rd line. 当我将应用程序导出为JAR并在另一台计算机上运行时,在第三行显示
java.io.FileNotFoundException
。 I added the "assets" folder to the build path, so it should be in the JAR. 我将“ assets”文件夹添加到了构建路径,因此它应该在JAR中。
Anyone know what's wrong here? 有人知道这是怎么回事吗?
FileOutputStream
just opens a local file. FileOutputStream
只是打开一个本地文件。 It should be absolute ( /home/user/...
or c:\\temp\\...
) or relative to the current directory. 它应该是绝对的(
/home/user/...
或c:\\temp\\...
)或相对于当前目录。 On Windows, for example, that's the directory containing the JAR, by default. 例如,在Windows上,默认情况下就是包含JAR的目录。
If you meant to package your classes
file into the JAR, then you should use getResourceAsStream
, as @guleryuz mentioned. 如果打算将
classes
文件打包到 JAR中,则应使用getResourceAsStream
,如@guleryuz所述。 The path should be either absolute starting from the CLASSPATH root (that is, the root of the JAR file), like "/assets/classes"
, or (better) relative to the package of the calling class. 路径应该是从CLASSPATH根目录(即JAR文件的根目录)开始的绝对路径,例如
"/assets/classes"
,或者相对于调用类的包而言是(更好)。
Speaking of classes, I'd strongly advise against using getClass()
because it's a polymorphic method. 说到类,我强烈建议不要使用
getClass()
因为它是一种多态方法。 There are two ways to get the class: by calling getClass()
on an object or by accessing the static class
“field”. 有两种获取类的方法:通过在对象上调用
getClass()
或通过访问静态class
“字段”。 If you have an instance of MyClass
called myObject
, then myObject.getClass()
and MyClass.class
are essentially the same thing. 如果您有一个名为
myObject
的MyClass
实例,则myObject.getClass()
和MyClass.class
本质上是同一件事。 But! 但! If your class is overridden by a class from another package, say,
TheirClass
, then, for an instance of TheirClass
, getClass()
will return TheirClass.class
, even if you are calling getClass()
from your code. 如果你的类是由类从另一个包覆盖,也就是说,
TheirClass
,那么,对于实例TheirClass
, getClass()
将返回TheirClass.class
,即使您呼叫getClass()
从你的代码。 So, unless your class is declared final
, it is always a bad idea to use getClass().getResource...
because you never know when someone overrides your class. 因此,除非将您的类声明为
final
,否则使用getClass().getResource...
始终是个坏主意getClass().getResource...
因为您永远不知道何时有人重写您的类。 And you're not supposed to know or even care! 而且您不应该知道甚至不在乎!
Given all that, say, you have a class called MyClass
in a package called my.package
. 假设所有这些,在名为
my.package
的包中就有一个名为MyClass
的类。 The JAR could have the following structure: JAR可以具有以下结构:
my/
package/
MyClass.class
assets/
classes
Then, calling MyClass.class.getResourceAsStream("assets/classes")
should do the trick. 然后,调用
MyClass.class.getResourceAsStream("assets/classes")
应该可以解决问题。 Alternatively, that could be MyClass.class.getResourceAsStream("/my/package/assets/classes")
. 另外,也可以是
MyClass.class.getResourceAsStream("/my/package/assets/classes")
。 Note that the absolute path does not start from the project directory, where you may have src
or src/main
or whatever your build system uses. 请注意,绝对路径并非从项目目录开始,您可能在其中有
src
或src/main
或您的构建系统使用的任何目录。 It is relative to the CLASSPATH root (that's right, the absolute path is relative to the CLASSPATH root, even if that sounds confusing). 它是相对于CLASSPATH根目录的(是的, 绝对路径是相对于CLASSPATH根目录的,即使这听起来很混乱)。 That is, it starts from the directory where your packages are.
也就是说,它从您的软件包所在的目录开始。
The last, but not least, is that if you use Maven-like build system (Maven or Gradle, for example), then Java sources go to src/main/java
, but resource files like your file go to src/main/resources
. 最后但并非最不重要的一点是,如果您使用类似Maven的构建系统(例如,Maven或Gradle),则Java源代码将转到
src/main/java
,而资源文件(如您的文件)将转到src/main/resources
。 They end up in exactly the same place in your JAR file. 它们最终位于您的JAR文件中的完全相同的位置。 That is,
src/main/java/package/MyClass.java
is compiled into package/MyClass.class
, and src/main/resources/package/assets/classes
go into package/assets/classes
. 也就是说,
src/main/java/package/MyClass.java
被编译为package/MyClass.class
,而src/main/resources/package/assets/classes
进入package/assets/classes
。 But in order for the build system to figure out what to do with your files, you must place them into the right directories: *.java
go to java
, resources go to resources
. 但是,为了使构建系统确定如何处理文件,必须将它们放置在正确的目录中:
*.java
转到java
,资源转到resources
。
So, assuming Maven-like conventions, the project structure should be 因此,假设类似Maven的约定,则项目结构应为
src/
main/
java/
my/
package/
MyClass.java
src/
main/
resources/
my/
package/
assets/
classes
Given such a structure, you'll get a JAR file with the structure like above. 有了这样的结构,您将获得具有上述结构的JAR文件。 Looks a bit crazy, but very useful once you get a hang of it.
看起来有点疯狂,但是一旦掌握了它,它就会非常有用。
If you're not using a Maven-like build system, then I have no idea how to configure Eclipse. 如果您不使用类似Maven的构建系统,那么我不知道如何配置Eclipse。 Different IDEs may have their own conventions, and I've always used Maven with Eclipse.
不同的IDE可能有各自的约定,并且我一直将Maven与Eclipse结合使用。 Some IDEs like to put Java sources and resources into the same directory tree, for example.
例如,某些IDE喜欢将Java源和资源放入同一目录树中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.