代码之家  ›  专栏  ›  技术社区  ›  Mark Cramer

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

  •  0
  • Mark Cramer  · 技术社区  · 9 年前

    我的Java应用程序有一个名为“classes”的本地文件(一个简单的 List<String> )位于名为“assets”的顶级文件夹中。当我从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(); }
    

    当我将应用程序导出为JAR并在另一台计算机上运行时,我会得到一个 java.io.FileNotFoundException 在第三行。我将“assets”文件夹添加到构建路径,因此它应该在JAR中。

    有人知道这里出了什么问题吗?

    1 回复  |  直到 9 年前
        1
  •  1
  •   Sergei Tachenov    9 年前

    FileOutputStream 只打开一个本地文件。它应该是绝对的( /home/user/... c:\temp\... )或相对于当前目录。例如,在Windows上,默认情况下,这是包含JAR的目录。

    如果你打算打包你的 classes 文件 getResourceAsStream 正如@guleryuz提到的。路径应该是从CLASSPATH根(即JAR文件的根)开始的绝对路径,如 "/asset‌​s/classes" ,或(更好)相对于调用类的包。

    说到课堂,我强烈建议不要使用 getClass() 因为这是一种多态方法。获取类的方法有两种:调用 获取类() 在对象上或通过访问静态 class 领域如果您有 MyClass 打电话 myObject 然后 myObject.getClass() MyClass.class 本质上是一样的。但是如果您的类被另一个包中的类覆盖,例如, TheirClass 那么,对于 他们的班级 , 获取类() 将返回 TheirClass.class ,即使您正在呼叫 获取类() 从…起 你的 final ,使用总是一个坏主意 getClass().getResource... 因为你永远不知道什么时候有人超越了你的课堂。你不应该知道甚至不在乎!

    考虑到所有这些,比如说,你有一个名为 类名 在名为 my.package JAR可以具有以下结构:

    my/
        package/
            MyClass.class
            assets/
                classes
    

    然后,呼叫 MyClass.class.getResourceAsStream("assets/classes") 应该会成功的。或者,也可以是 MyClass.class.getResourceAsStream("/my/package/assets/classes") 。请注意,绝对路径是 从项目目录开始,您可能已经 src src/main 或您的构建系统使用的任何内容。它是相对于CLASSPATH根目录的(没错 完全的 路径是 相对的 到CLASSPATH根目录,即使这听起来很混乱)。也就是说,它从包所在的目录开始。

    最后,但并非最不重要的是,如果使用类似Maven的构建系统(例如Maven或Gradle),那么Java源代码将转到 src/main/java ,但像您的文件这样的资源文件转到 src/main/resources 。它们在JAR文件中的位置完全相同。那就是, src/main/java/package/MyClass.java 编译为 package/MyClass.class src/main/resources/package/assets/classes 进入 package/assets/classes 。但为了让生成系统知道如何处理您的文件,您必须将它们放在正确的目录中: *.java java ,资源转到 resources .

    因此,假设类似Maven的约定,项目结构应该是

    src/
        main/
            java/
                my/
                    package/
                        MyClass.java
    src/
        main/
            resources/
                my/
                    package/
                        assets/
                            classes
    

    给定这样的结构,您将得到一个具有上述结构的JAR文件。看起来有点疯狂,但一旦你掌握了窍门,就会非常有用。

    如果您没有使用类似Maven的构建系统,那么我不知道如何配置Eclipse。不同的IDE可能有自己的约定,我一直在Eclipse中使用Maven。例如,一些IDE喜欢将Java源代码和资源放在同一个目录树中。