You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

IntelliJ打包Jar后无法读取XML文件问题求助

Hey there! Let's fix this jar file XML loading issue once and for all 😊

The Root Cause

Your current code relies on relative paths like src\ItemsXML\items.xml which work fine in IntelliJ because the project root is your working directory. But when you package into a jar:

  • The src directory doesn't exist inside the jar—your XML files get bundled directly into the jar's resource structure
  • You can't use File or FileInputStream to read files inside a jar, since they're not physical files on disk anymore

Step 1: Configure Your Resource Directories Properly

First, make sure IntelliJ packages your XML folders correctly:

  • Right-click the ItemsXML and MonsterXML folders in your project
  • Select Mark Directory as → Resources Root
    This ensures all files in these folders are copied to the root of your jar (or preserved in their relative structure) during the build.

Step 2: Fix Single XML File Reading

Replace your disk-path based reading with a classloader stream, which works both in IDE and jar:

public void ReadItemXMLfile() {
    try {
        // Load the XML as a resource stream instead of using a disk path
        InputStream inputStream = getClass().getResourceAsStream("/ItemsXML/items.xml");
        if (inputStream == null) {
            throw new IOException("Could not find items.xml in resources");
        }

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document doc = builder.parse(inputStream); // Parse from the stream

        XPathFactory xpathfactory = XPathFactory.newInstance();
        XPath xpath = xpathfactory.newXPath();
        XPathExpression expr = xpath.compile("/items/item");

        Object result = expr.evaluate(doc, XPathConstants.NODESET);
        NodeList nodes = (NodeList) result;

        for (int i = 0; i < nodes.getLength(); i++) {
            Node testNode = nodes.item(i);
            if (testNode.getNodeType() == Node.ELEMENT_NODE) {
                Element element = (Element) testNode;
                String idFromItemXml = element.getAttribute("id");
                String itemNameFromItemXml = element.getAttribute("name");

                for (MonsterXML monster : monstersArrayList) {
                    for (MonsterLootXML loot : monster.getLootableItems()) {
                        if (loot.getId().equals(idFromItemXml)) {
                            loot.setName(itemNameFromItemXml.substring(0, 1).toUpperCase() + itemNameFromItemXml.substring(1));
                        }
                    }
                }
            }
        }
        inputStream.close(); // Don't forget to close the stream!
    } catch (ParserConfigurationException | IOException | XPathExpressionException | SAXException e) {
        e.printStackTrace();
    }
}

Step 3: Fix Multiple XML File Reading

Reading a directory of XMLs requires handling both IDE (file system) and jar (bundle) environments. Here's a compatible solution:

public void ReadMonsterXMLfiles() {
    try {
        String resourceDir = "/MonsterXML/";
        URL dirUrl = getClass().getResource(resourceDir);
        if (dirUrl == null) {
            throw new IOException("MonsterXML resource directory not found");
        }

        List<InputStream> xmlStreams = new ArrayList<>();

        // Handle IDE (file system) case
        if (dirUrl.getProtocol().equals("file")) {
            File dir = new File(dirUrl.toURI());
            File[] files = dir.listFiles((d, name) -> name.endsWith(".xml"));
            if (files != null) {
                for (File file : files) {
                    xmlStreams.add(new FileInputStream(file));
                }
            }
        }
        // Handle jar file case
        else if (dirUrl.getProtocol().equals("jar")) {
            String jarPath = dirUrl.getPath().substring(5, dirUrl.getPath().indexOf("!"));
            JarFile jarFile = new JarFile(jarPath);
            Enumeration<JarEntry> entries = jarFile.entries();
            
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                String entryName = entry.getName();
                if (entryName.startsWith("MonsterXML/") && entryName.endsWith(".xml") && !entry.isDirectory()) {
                    xmlStreams.add(jarFile.getInputStream(entry));
                }
            }
            jarFile.close();
        }

        // Parse each XML stream
        for (InputStream inputStream : xmlStreams) {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(inputStream);

            XPathFactory xpathfactory = XPathFactory.newInstance();
            XPath xpath = xpathfactory.newXPath();
            XPathExpression expr = xpath.compile("/monster/@name | /monster/@experience | /monster/@manacost | /monster/health/@now");
            Object result = expr.evaluate(doc, XPathConstants.NODESET);
            NodeList nodes = (NodeList) result;

            MonsterXML monsterXML = new MonsterXML();
            // Match the node order to your XPath expression!
            monsterXML.setExperience(nodes.item(0).getTextContent());
            monsterXML.setManaToSummon(nodes.item(1).getTextContent());
            monsterXML.setName(nodes.item(2).getTextContent());
            monsterXML.setHealth(nodes.item(3).getTextContent());
            monsterXML.setName(monsterXML.getName().substring(0, 1).toUpperCase() + monsterXML.getName().substring(1));

            // Parse loot data
            expr = xpath.compile("/monster/loot//item");
            result = expr.evaluate(doc, XPathConstants.NODESET);
            nodes = (NodeList) result;

            for (int i = 0; i < nodes.getLength(); i++) {
                Node testNode = nodes.item(i);
                if (testNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element element = (Element) testNode;
                    MonsterLootXML monsterLootXML = new MonsterLootXML();
                    monsterLootXML.setId(element.getAttribute("id"));
                    monsterLootXML.setLootChance(element.getAttribute("chance"));
                    monsterLootXML.setLootChance(Calculations.correctDropChanceNumber(monsterLootXML.getLootChance()));

                    monsterLootXML.setAmount(element.hasAttribute("countmax") ? element.getAttribute("countmax") : "1");
                    monsterXML.addLootableItems(monsterLootXML);
                }
            }
            monstersArrayList.add(monsterXML);
            inputStream.close();
        }

    } catch (Exception e) {
        e.printStackTrace();
    }
}

Quick Testing Tip

After making these changes:

  1. Rebuild your artifact in IntelliJ
  2. Run the jar via command line: java -jar application.jar to confirm it loads all XML data correctly

If you hit any snags, feel free to reach out on Discord—I'm happy to help debug further!

内容的提问来源于stack exchange,提问作者Lasse

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 10:27:50