如何从可执行 Jar 文件中加载 xml 资源文件并将其保存到 jar 所在的文件夹中?

How can I load an xml resource file from within an executible Jar file and save it to the folder the jar is located in?

我有一个自定义 java 服务器。它使用外部 xml 配置文件。 我有一些命令行选项可以帮助用户,通常用于显示帮助文件、设置端口等...

我最近添加了一个命令来为服务器生成默认配置文件。这是一个 xml 文件。在研究了我的选择之后,在 jar 中打包一个默认的 xml 文件似乎是可行的方法,但我显然遗漏了一些东西。 到目前为止,我的代码如下所示:

public class ResourceLoader {

    private File outFile = null;
    private Reader fileReader = null;
    private Writer fileWriter = null;
    private InputStream is = null;
    private char[] buffer = null;

    public ResourceLoader() {
        outFile = new File("default-server.xml");
    }

    public void generateDefaultServerXml() {

        is = ResourceLoader.class.getResourceAsStream("/default-server.xml");

        if (is == null) {
            System.out.println("Configuraiton File generation failed. The InputStream is null.");
        } else {

            fileReader = new InputStreamReader(is);
        }

        buffer = new char[4096];
        FileOutputStream fos;

        try {

            fos = new FileOutputStream(outFile);
            fileWriter = new OutputStreamWriter(fos);

            while (fileReader.read(buffer) != -1) {
                fileWriter.write(buffer, 0, buffer.length);
                fileWriter.flush();
                buffer = new char[4096];
            }

        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        try {

            fileReader.close();
            fileWriter.close();

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

当我在 eclipse 中 运行 上面的代码工作得很好,但是最初,在我导出 jar 文件后,当我 运行 时服务器找不到 default-server.xml 文件来自终端的命令。
该文件本身位于一个名为 main.resources 的包中,还有一些其他配置文件和上面的 class.

我已将 ResourceLoader.class 移至另一个包。这样做之后,服务器似乎在 main.resources 包中找到了 xml 文件(InputStream 不是 null),但是生成的 default-server.xml 文件是空的。

同样,当我在 eclipse 中 运行 时,这一切都工作得很好,只有在我导出项目并尝试从终端发出命令后,进程才会失败。我究竟做错了什么?

上面的class被实例化,generateDefaultServerXml()被调用,来自服务器的main方法。

编辑: 我写 default-server.xml 的路径有点错误。现在我已经调整了它,当我在 Eclipse 中 运行 它时,代码完全按照预期工作。资源以正确的方式读取,并写入文件的正确位置。但是当我从 jar 文件中尝试同样的事情时它仍然不起作用。

这里的问题是因为您将应用程序打包为 jar。调用外部资源的过程是完全不同的。

您需要有一个文件夹结构

root
--your jar
--your xml file

如果应用程序使用 jar 中的 default-server.xml 文件,您的代码应该可以工作。 否则,如果您想使用 external default xml file,请替换代码中的以下行。

  is = new FileInputStream("./default-server.xml");

如果您想要的输出文件位于 root 位置,请使用下面的代码

 public ResourceLoader() {
        outFile = new File("./default-server.xml");
    }

根据讨论的替代代码

public class ResourceLoader {

    public void generateDefaultServerXml() {
        try {
        String defaultxmltext  =readFileToString("/default-server.xml");
        writeFileFromInputString(defaultxmltext);
        } catch (IOException e) {
            //exception
        }
    }

    public static void writeFileFromInputString(String everything) throws IOException {

        try (BufferedWriter writer = new BufferedWriter(new FileWriter("./default-server.xml"))) {
            everything = everything.replaceAll("\n", System.getProperty("line.separator"));
            writer.write(everything);
        }
    }

    public static String readFileToString(String path) throws IOException {
        String everything = null;
        try (BufferedReader br = new BufferedReader(new FileReader(path))) {
            StringBuilder sb = new StringBuilder();
            String line = br.readLine();

            while (line != null) {
                sb.append(line);
                sb.append(System.lineSeparator());
                line = br.readLine();
            }
            everything = sb.toString();
        }
        return everything;
    }
}

希望对您有所帮助

当前行 ResourceLoader.class.getResourceAsStream("/default-server.xml") 意味着您正在尝试从类路径的根目录加载名为 default-server.xml 的资源,或者更简单地说,从 jar 文件的根目录。这意味着 xml 文件不应位于 jar 文件内的任何包中。

当你 assemble 你的 jar 文件然后 运行 jar tf my.jar 在它上面时,你看到你的 default-server.xml 文件了吗?它位于某个包中还是位于 jar 文件的根目录中?

考虑一下您的文件位于 src/main/resources 试试这个

getClass().getClassLoader().getResource(fileName)

据我所知,您的主要问题是您传递的路径错误,因为您提到 xml 在 main.resources 下,您需要将其添加到路径中尝试加载文件,这是一段适合您的示例代码

   Scanner sc = null;
   PrintWriter writer = null;
   try {
      sc = new Scanner(getClass().getResourceAsStream("main/resources/server.xml"));
      writer = new PrintWriter("./default_server.xml", "UTF-8");
      while(sc.hasNextLine()) {
         writer.println(sc.nextLine());
      }
   } catch (Exception e) {
   } finally {
      if(sc != null) {
         sc.close();
      }
      if(writer != null){
         writer.close();
      }
   }