简体   繁体   中英

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?

I have a custom java server. It uses an external xml config file. I have some command line options to help the user, the usual stuff for showing a help file, setting ports, etc...

I've recently added a command to generate a default config file for the server. It's an xml file. After researching my options, packing a default xml file in the jar seemed to be the way to go, but I'm obviously missing something. So far my code looks like this:

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();
        }
    }
}

The code above works perfectly fine when I run it in eclipse, but intitially, after I export the jar file the server could not locate the default-server.xml file when I run the command from the terminal.
The file itself is located in a package called main.resources along with some other config files and the above class.

I have since moved the ResourceLoader.class to another package. After doing that the server seems to find the xml file in the main.resources package ( InputStream is not null ) but the resulting generated default-server.xml file is empty.

Again, this all works perfectly well when I run it in eclipse, it's only after I export the project and try issue the command from the terminal that the process fails. What am I doing wrong?

The above class is instantiated, and the generateDefaultServerXml() is called, from the main method of the server.

EDIT: My path for writing default-server.xml was slightly wrong. Now that I've adjusted it the code works exactly as expected when I run it in Eclipse. The resource is read in the correct way, and written to the file in the correct location. But it still doesn't work when I try the same thing from the jar file.

The problem here is since you are packaging the application as a jar. The procedure to call an external resource is quite different.

You need to have a folder structure as

root
--your jar
--your xml file

Your code shallwork if the application is using an default-server.xml file inside the jar. Otherwise, Replace below line in your code if you want to use an external default xml file .

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

If the output file you want at root location the use below code

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

Alternate code as per discussion

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;
    }
}

Hope this helps

You current line ResourceLoader.class.getResourceAsStream("/default-server.xml") means that you are trying to load a resource named default-server.xml from the root of your classpath, or put simpler, from the root of your jar file. This means that xml file should NOT be in any package inside the jar file.

When you assemble your jar file and then run jar tf my.jar on it, do you see your default-server.xml file? Does it reside in some package or in the root of the jar file?

考虑您的文件位于src / main / resources上尝试

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

well as far as i can see your main problem is that you are passing the wrong path, since you mentioned the xml is under main.resources you will need to add this to the path when trying to load the file, here is a sample piece of code that should work for you

   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();
      }
   }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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