มองไม่เห็นไฟล์ภายในขวดสำหรับฤดูใบไม้ผลิ


107

ทั้งหมด

ฉันสร้างไฟล์ jar ที่มี MANIFEST.MF ต่อไปนี้อยู่ภายใน:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.3
Created-By: 1.6.0_25-b06 (Sun Microsystems Inc.)
Main-Class: my.Main
Class-Path: . lib/spring-core-3.2.0.M2.jar lib/spring-beans-3.2.0.M2.jar

ในรูทมีไฟล์ชื่อ my.config ซึ่งอ้างอิงใน spring-context.xml ของฉันเช่นนี้:

<bean id="..." class="...">
    <property name="resource" value="classpath:my.config" />
</bean>

หากฉันเรียกใช้ jar ทุกอย่างดูดียกเว้นการโหลดไฟล์นั้น ๆ :

Caused by: java.io.FileNotFoundException: class path resource [my.config] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/D:/work/my.jar!/my.config
        at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:205)
    at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:52)
    at eu.stepman.server.configuration.BeanConfigurationFactoryBean.getObject(BeanConfigurationFactoryBean.java:32)
    at eu.stepman.server.configuration.BeanConfigurationFactoryBean.getObject(BeanConfigurationFactoryBean.java:1)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)
    ... 22 more
  • ชั้นเรียนจะโหลดจากภายในโถ
  • สปริงและการอ้างอิงอื่น ๆ ถูกโหลดจากขวดที่แยกจากกัน
  • บริบทสปริงถูกโหลด (ClassPathXmlApplicationContext ใหม่ ("spring-context / applicationContext.xml"))
  • my.properties ถูกโหลดลงใน PropertyPlaceholderConfigurer ("classpath: my.properties")
  • ถ้าฉันใส่ไฟล์. config ของฉันนอกระบบไฟล์และเปลี่ยน url ทรัพยากรเป็น 'file:' ดูเหมือนว่าทุกอย่างจะเรียบร้อยดี ...

เคล็ดลับใด ๆ

คำตอบ:


217

ถ้าไฟล์ spring-context.xml และ my.config อยู่คนละขวดคุณจะต้องใช้classpath*:my.config?

ข้อมูลเพิ่มเติมที่นี่

ตรวจสอบให้แน่ใจว่าคุณresource.getInputStream()ไม่ได้ใช้งานresource.getFile()เมื่อโหลดจากภายในไฟล์ jar


1
พวกเขาอยู่ใน jar เดียวกัน แต่ฉันลองใช้วิธีแก้ปัญหาของคุณด้วยผลลัพธ์เดียวกัน: java.io.FileNotFoundException: class path resource [classpath *: my.config] ไม่สามารถแก้ไขเป็น URL ได้เนื่องจากไม่มีอยู่
BTakacs

14
เมื่อมองอีกครั้งรหัสการโทรบางส่วนของคุณ (อาจเป็น BeanConfigurationFactoryBean) กำลังพยายามโหลด java.io.File ไฟล์หมายถึงไฟล์บนระบบไฟล์ซึ่งรายการใน jar ไม่ใช่ รหัสการโทรควรใช้ resource.getInputStream แทนเพื่อโหลดออกจาก jar
sbk

60
... และนี่คือคำตอบ ... ขอบคุณ! ภายในขวดไม่ใช้ resource.getFile () :-)
BTakacs

2
มีโอกาส "ทำไม" ข้างหลังไม่ใช้ getFile () ในโถ? มันเป็นเพียงไฟล์ที่อยู่ใน Jar และด้วยเหตุนี้ "ไฟล์" จึงเป็นไฟล์ jar ??
RockMeetHardplace

8
แค่นั้นแหละ. java.io.File แทนไฟล์บนระบบไฟล์ในโครงสร้างไดเร็กทอรี Jar เป็นไฟล์ java.io.File แต่สิ่งใดก็ตามในไฟล์นั้นอยู่ไกลเกินเอื้อมของ java.io.File เท่าที่เกี่ยวข้องกับ java จนกว่าจะไม่มีการบีบอัด class ในไฟล์ jar ก็ไม่ต่างจาก word ในเอกสาร word
sbk

53

ฉันรู้ว่าคำถามนี้ได้รับคำตอบแล้ว อย่างไรก็ตามสำหรับผู้ที่ใช้สปริงบูตลิงค์นี้ช่วยฉันได้ - https://smarterco.de/java-load-file-classpath-spring-boot/

อย่างไรก็ตามสิ่งที่resourceLoader.getResource("classpath:file.txt").getFile();ทำให้เกิดปัญหานี้และความคิดเห็นของ sbk:

แค่นั้นแหละ. java.io.File แทนไฟล์บนระบบไฟล์ในโครงสร้างไดเร็กทอรี Jar เป็นไฟล์ java.io.File แต่สิ่งใดก็ตามในไฟล์นั้นอยู่ไกลเกินเอื้อมของ java.io.File เท่าที่เกี่ยวข้องกับ java จนกว่าจะไม่มีการบีบอัด class ในไฟล์ jar ก็ไม่ต่างจาก word ในเอกสาร word

ช่วยให้ฉันเข้าใจว่าทำไมต้องใช้getInputStream()แทน มันใช้ได้กับฉันตอนนี้!

ขอบคุณ!


39

ในแพ็คเกจขวดสปริงฉันใช้ใหม่ClassPathResource(filename).getFile()ซึ่งมีข้อยกเว้น:

ไม่สามารถแก้ไขเป็นพา ธ ไฟล์แบบสัมบูรณ์ได้เนื่องจากไม่ได้อยู่ในระบบไฟล์: jar

แต่การใช้new ClassPathResource(filename).getInputStream()จะช่วยแก้ปัญหานี้ได้ getInputStream()เหตุผลก็คือว่าแฟ้มการกำหนดค่าในขวดไม่ได้อยู่ในต้นไม้ไฟล์ของระบบปฏิบัติการเพื่อการใช้งานที่ต้อง


2

ฉันมีปัญหาคล้ายกันเมื่อใช้ Tomcat6.x และไม่มีคำแนะนำใดที่ฉันพบว่าช่วยได้ ในตอนท้ายฉันลบworkโฟลเดอร์ (ของ Tomcat) และปัญหาก็หายไป

ฉันรู้ว่ามันไร้เหตุผล แต่เพื่อวัตถุประสงค์ในการจัดทำเอกสาร ...


1

คำตอบโดย @sbk คือวิธีที่เราควรทำในสภาพแวดล้อมสปริงบูต (นอกเหนือจาก @Value ("$ {classpath *:})) ในความคิดของฉัน แต่ในสถานการณ์ของฉันมันไม่ได้ผลหากดำเนินการจากแบบสแตนด์อโลน โถ.. ฉันอาจจะทำอะไรผิด

แต่นี่อาจเป็นอีกวิธีหนึ่งในการทำเช่นนี้

InputStream is = this.getClass().getClassLoader().getResourceAsStream(<relative path of the resource from resource directory>);

1

ฉันมีปัญหาที่ซับซ้อนมากขึ้นเนื่องจากฉันมีไฟล์ที่มีชื่อเดียวกันมากกว่าหนึ่งไฟล์ไฟล์หนึ่งอยู่ในโถ Spring Boot หลักและไฟล์อื่น ๆ อยู่ในไหภายในโถไขมันหลัก วิธีแก้ปัญหาของฉันคือได้รับทรัพยากรทั้งหมดที่มีชื่อเดียวกันและหลังจากนั้นก็รับทรัพยากรที่ฉันต้องการกรองตามชื่อแพ็คเกจ ในการรับไฟล์ทั้งหมด:

ResourceLoader resourceLoader = new FileSystemResourceLoader();
final Enumeration<URL> systemResources = resourceLoader.getClassLoader().getResources(fileNameWithoutExt + FILE_EXT);

0

ผมมีปัญหาซ้ำโหลดทรัพยากรใน app resource.getInputStreamฤดูใบไม้ผลิของฉันและพบว่าปัญหาผมควรจะใช้ นี่คือตัวอย่างที่แสดงวิธีการอ่านซ้ำในไฟล์ทั้งหมดในconfig/myfilesนั้นjsonไฟล์

Example.java

private String myFilesResourceUrl = "config/myfiles/**/";
private String myFilesResourceExtension = "json";

ResourceLoader rl = new ResourceLoader();

// Recursively get resources that match. 
// Big note: If you decide to iterate over these, 
// use resource.GetResourceAsStream to load the contents
// or use the `readFileResource` of the ResourceLoader class.
Resource[] resources = rl.getResourcesInResourceFolder(myFilesResourceUrl, myFilesResourceExtension);

// Recursively get resource and their contents that match. 
// This loads all the files into memory, so maybe use the same approach 
// as this method, if need be.
Map<Resource,String> contents = rl.getResourceContentsInResourceFolder(myFilesResourceUrl, myFilesResourceExtension);

ResourceLoader.java

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.StreamUtils;

public class ResourceLoader {
  public Resource[] getResourcesInResourceFolder(String folder, String extension) {
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    try {
      String resourceUrl = folder + "/*." + extension;
      Resource[] resources = resolver.getResources(resourceUrl);
      return resources;
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  public String readResource(Resource resource) throws IOException {
    try (InputStream stream = resource.getInputStream()) {
      return StreamUtils.copyToString(stream, Charset.defaultCharset());
    }
  }

  public Map<Resource, String> getResourceContentsInResourceFolder(
      String folder, String extension) {
    Resource[] resources = getResourcesInResourceFolder(folder, extension);

    HashMap<Resource, String> result = new HashMap<>();
    for (var resource : resources) {
      try {
        String contents = readResource(resource);
        result.put(resource, contents);
      } catch (IOException e) {
        throw new RuntimeException("Could not load resource=" + resource + ", e=" + e);
      }
    }
    return result;
  }
}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.