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
srcdirectory doesn't exist inside the jar—your XML files get bundled directly into the jar's resource structure - You can't use
FileorFileInputStreamto 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
ItemsXMLandMonsterXMLfolders 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:
- Rebuild your artifact in IntelliJ
- Run the jar via command line:
java -jar application.jarto 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
相关产品推荐
相关产品推荐

