简体   繁体   English

导出的JAR无法读取本地文件

[英]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 "/asset‌​s/classes" , or (better) relative to the package of the calling class. 路径应该是从CLASSPATH根目录(即JAR文件的根目录)开始的绝对路径,例如"/asset‌​s/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. 如果您有一个名为myObjectMyClass实例,则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 ,那么,对于实例TheirClassgetClass()将返回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. 请注意,绝对路径并非从项目目录开始,您可能在其中有srcsrc/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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM