Файл всередині банку не видно навесні


103

Усі

Я створив файл 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 ("шлях до класу: my.properties")
  • якщо я розміщу свій файл .config за межами файлової системи та зміню URL-адресу ресурсу на 'файл:', все здається в порядку ...

Якісь поради?

Відповіді:


211

Якщо ваші файли spring-context.xml і my.config знаходяться в різних банках, тоді вам потрібно буде використовувати classpath*:my.config?

Більше інформації тут

Крім того, переконайтеся, що ви використовуєте resource.getInputStream()не resource.getFile()під час завантаження зсередини файлу jar.


1
Вони знаходяться в одній банці, але я спробував ваше рішення з тим самим результатом: java.io.FileNotFoundException: ресурс шляху до класу [classpath *: my.config] неможливо вирішити до URL, оскільки він не існує
BTakacs

14
Переглядаючи ще раз, деякі з вашого телефонного коду (можливо, BeanConfigurationFactoryBean) намагаються завантажити файл java.io.File. Файл відноситься до файлів у файловій системі, записів яких не є. Замість цього для виклику коду слід використовувати ресурс.getInputStream для завантаження з банки.
sbk

57
... і ЦЕ відповідь ... Дякую! Всередині банки не використовуйте resource.getFile () :-)
BTakacs

2
будь-який шанс є "чому?" позаду не використовуючи getFile () всередині банки? Це просто, що файл знаходиться всередині Jar, а значить, "файл" - це файл jar ??
RockMeetHardplace

8
Це воно. Файл java.io.File представляє файл у файловій системі у структурі каталогів. Jar - це файл java.io.File. Але все, що знаходиться в цьому файлі, поза межами досяжності java.io.File. Що стосується java, поки вона не стискається, клас у файлі jar не відрізняється від слова у текстовому документі.
sbk

50

Я знаю, на це питання вже відповіли. Однак тим, хто використовує весняне завантаження, це посилання допомогло - 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, поки вона не стискається, клас у файлі jar не відрізняється від слова у текстовому документі.

допомогло мені зрозуміти, чому використовувати getInputStream()замість цього. Зараз у мене це працює!

Дякую!


37

У пакеті весняної банки я використовую новий ClassPathResource(filename).getFile(), який викидає виняток:

не можна вирішити абсолютний шлях до файлу, оскільки він не знаходиться у файловій системі: jar

Але використання нового ClassPathResource(filename).getInputStream()вирішить цю проблему. Причина полягає в тому, що файл файлу конфігурації в банку не існує у дереві файлів операційної системи, тому потрібно використовувати getInputStream().


2

У мене була подібна проблема при використанні Tomcat6.x, і жодна порада, яку я знайшов, не допомагала. Наприкінці я видалив workпапку (Tomcat), і проблема зникла.

Я знаю, що це нелогічно, але з метою документації ...


1

Відповідь @sbk - це те, як ми повинні це робити у середовищі spring-boot (окрім @Value ("$ {classpath *:})), на мій погляд. Але в моєму сценарії це не спрацювало, якщо виконати з автономного jar..може я зробив щось не так.

Але це може бути інший спосіб зробити це,

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

У мене виникла проблема з рекурсивним завантаженням ресурсів у моїй програмі Spring, і я виявив, що проблема полягає в тому, що я повинен використовувати resource.getInputStream. Ось приклад, що показує, як рекурсивно читати всі файли, config/myfilesщо є jsonфайлами.

Приклад.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;
  }
}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.