在 SpringBoot 中从资源文件夹读取文件

我正在使用 Spring Boot 和 json-schema-validator。我试图从 resources文件夹读取一个名为 jsonschema.json的文件。我尝试了几种不同的方法,但我不能让它工作。这是我的原则。

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("jsonschema.json").getFile());
JsonNode mySchema = JsonLoader.fromFile(file);

这是文件的位置。

enter image description here

这里我可以看到 classes文件夹中的文件。

enter image description here

但是当我运行代码时,我会得到以下错误。

jsonSchemaValidator error: java.io.FileNotFoundException: /home/user/Dev/Java/Java%20Programs/SystemRoutines/target/classes/jsonschema.json (No such file or directory)

我的代码哪里做错了?

421563 次浏览

非常简短的回答: 您正在类加载器类的作用域中而不是您的目标类中寻找资源。这应该会奏效:

File file = new File(getClass().getResource("jsonschema.json").getFile());
JsonNode mySchema = JsonLoader.fromFile(file);

另外,阅读这篇文章可能会有所帮助:

附注: 有一种情况,一个项目在一台机器上编译,然后在另一台机器上或在 Docker 内部启动。在这样的场景中,资源文件夹的路径是无效的,您需要在运行时获取它:

ClassPathResource res = new ClassPathResource("jsonschema.json");
File file = new File(res.getPath());
JsonNode mySchema = JsonLoader.fromFile(file);

2020年更新

除此之外,如果您希望将资源文件读取为 String,例如在您的测试中,您可以使用以下静态 utils 方法:

public static String getResourceFileAsString(String fileName) {
InputStream is = getResourceFileAsInputStream(fileName);
if (is != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
return (String)reader.lines().collect(Collectors.joining(System.lineSeparator()));
} else {
throw new RuntimeException("resource not found");
}
}


public static InputStream getResourceFileAsInputStream(String fileName) {
ClassLoader classLoader = {CurrentClass}.class.getClassLoader();
return classLoader.getResourceAsStream(fileName);
}

用法示例:

String soapXML = getResourceFileAsString("some_folder_in_resources/SOPA_request.xml");

困在同一个问题上,这对我有帮助

URL resource = getClass().getClassLoader().getResource("jsonschema.json");
JsonNode jsonNode = JsonLoader.fromURL(resource);

在花了很多时间试图解决这个问题之后,终于找到了一个有效的解决方案。该解决方案利用了 Spring 的 ResourceUtils。 也可以用于 json 文件。

感谢 Lokesh Gupta: 博客写得很好的一页

enter image description here

package utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ResourceUtils;


import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.io.File;




public class Utils {


private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class.getName());


public static Properties fetchProperties(){
Properties properties = new Properties();
try {
File file = ResourceUtils.getFile("classpath:application.properties");
InputStream in = new FileInputStream(file);
properties.load(in);
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
return properties;
}
}

回答一些关于评论的问题:

我很确定我用 java -jar target/image-service-slave-1.0-SNAPSHOT.jar在 Amazon EC2上运行了这个程序

看看我的 github 回购 https://github.com/johnsanthosh/image-service : 找出在 JAR 中运行它的正确方法。

在资源中创建 json 文件夹作为子文件夹,然后在文件夹中添加 json 文件,然后可以使用以下代码: enter image description here

import com.fasterxml.jackson.core.type.TypeReference;

InputStream is = TypeReference.class.getResourceAsStream("/json/fcmgoogletoken.json");

这个在多克可以用。

如果在“资源”文件夹下有示例配置文件夹 我试过这门课,希望有用

File file = ResourceUtils.getFile("classpath:config/sample.txt")


//Read File Content
String content = new String(Files.readAllBytes(file.toPath()));
System.out.println(content);

这是我的解决办法。可以帮助别人;

它返回 InputStream,但是我假设您也可以从中读取。

InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("jsonschema.json");

在这里可以看到我的答案: https://stackoverflow.com/a/56854431/4453282

import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

用这两个进口货。

宣布

@Autowired
ResourceLoader resourceLoader;

在某些功能中使用它

Resource resource=resourceLoader.getResource("classpath:preferences.json");

在您的情况下,由于需要该文件,可以使用以下方法

File file = resource.getFile()

参考文献: < a href = “ http://Frugalisminds.com/spring/load-file-classspath-spring-boot/”rel = “ norefrer”> http://frugalisminds.com/spring/load-file-classpath-spring-boot/ 正如在前面的答案中已经提到的,不要使用 ResourceUtils,它在部署 JAR 之后不起作用,这将在 IDE 中以及部署之后起作用

花了太多时间回到这一页,所以就把这个留在这里:

File file = new ClassPathResource("data/data.json").getFile();

下面是我的工作代码。

List<sampleObject> list = new ArrayList<>();
File file = new ClassPathResource("json/test.json").getFile();
ObjectMapper objectMapper = new ObjectMapper();
sampleObject = Arrays.asList(objectMapper.readValue(file, sampleObject[].class));

希望对你有帮助!

对我来说,这个 bug 有两个修复方法。

  1. XML 文件,该文件被命名为 SAMPLE.XML,当部署到 awsec2时,甚至导致下面的解决方案失败。修复方法是将其重命名为 new _ sample.xml 并应用下面给出的解决方案。
  2. 解决方案 Https://medium.com/@jonathan.henrique.smtp/reading-files-in-resource-path-from-jar-artifact-459ce00d2130

我使用 Spring 引导作为 jar 并部署到 awsec2 该解决方案的 Java 变体如下:

package com.test;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
import java.util.stream.Stream;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;




public class XmlReader {


private static Logger LOGGER = LoggerFactory.getLogger(XmlReader.class);


public static void main(String[] args) {




String fileLocation = "classpath:cbs_response.xml";
String reponseXML = null;
try (ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext()){


Resource resource = appContext.getResource(fileLocation);
if (resource.isReadable()) {
BufferedReader reader =
new BufferedReader(new InputStreamReader(resource.getInputStream()));
Stream<String> lines = reader.lines();
reponseXML = lines.collect(Collectors.joining("\n"));


}
} catch (IOException e) {
LOGGER.error(e.getMessage(), e);
}
}
}

将来自 resources 目录中的类路径的资源解析为 String 的最简单方法是下面一行。

作为字符串(使用 Spring 库) :

         String resource = StreamUtils.copyToString(
new ClassPathResource("resource.json").getInputStream(), defaultCharset());

这个方法使用 StreamUtils实用程序,并以简洁紧凑的方式将文件作为输入流传输到 String 中。

如果你想让文件作为一个字节数组,你可以使用基本的 Java 文件 I/O 库:

作为字节数组(使用 Java 库) :

byte[] resource = Files.readAllBytes(Paths.get("/src/test/resources/resource.json"));

我认为问题在于放置项目的文件夹名称的空间。 /home/user/Dev/Java/Java% 20Programs/SystemRoutines/target/classes/jsonschema.json

在 Java 程序之间有一定的空间。重命名文件夹名可以让它正常工作

如果您使用的是 springjackson(大多数较大的应用程序都会使用) ,那么使用一个简单的泛线笔:

JsonNode json = new ObjectMapper().readTree(new ClassPathResource("filename").getFile());

Spring 提供了可用于加载文件的 ResourceLoader

@Autowired
ResourceLoader resourceLoader;




// path could be anything under resources directory
File loadDirectory(String path){
Resource resource = resourceLoader.getResource("classpath:"+path);
try {
return resource.getFile();
} catch (IOException e) {
log.warn("Issue with loading path {} as file", path);
}
return null;
}

指的是这个 链接

如果在项目中使用 maven 资源过滤器,则需要配置将在 pom.xml 中加载什么类型的文件。如果不这样做,无论您选择加载哪个类,都不会找到资源。

Pom.xml

<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
<include>**/*.yml</include>
<include>**/*.yaml</include>
<include>**/*.json</include>
</includes>
</resource>
</resources>

下面的代码可以在 IDE 中工作,并在终端中作为 jar 运行,

import org.springframework.core.io.Resource;


@Value("classpath:jsonschema.json")
Resource schemaFile;
    

JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4);
JsonSchema jsonSchema = factory.getSchema(schemaFile.getInputStream());

我有同样的问题,因为我只是得到文件路径发送到文件输入流,我这样做。

    String pfxCertificate ="src/main/resources/cert/filename.pfx";
String pfxPassword = "1234";
FileInputStream fileInputStream = new FileInputStream(pfxCertificate));

使用 SpringGetFile (),您不必担心绝对路径:)

 private String readDictionaryAsJson(String filename) throws IOException {
String fileContent;
try {
File file = ResourceUtils.getFile("classpath:" + filename);
Path path = file.toPath();
Stream<String> lines = Files.lines(path);
fileContent = lines.collect(Collectors.joining("\n"));
} catch (IOException ex) {
throw ex;
}
return new fileContent;
}

如何可靠地获取资源

要可靠地从 Spring Boot 应用程序中的资源获取文件:

  1. 找到一种传递抽象资源的方法,例如,InputStreamURL而不是 File
  2. 使用框架工具获取资源

示例: 从 resources读取文件

public class SpringBootResourcesApplication {
public static void main(String[] args) throws Exception {
ClassPathResource resource = new ClassPathResource("/hello", SpringBootResourcesApplication.class);
try (InputStream inputStream = resource.getInputStream()) {
String string = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
System.out.println(string);
}
}
}
  • ClassPathResource 是 Spring 对 Resource的实现——加载 资源的抽象方式:

  • 项目结构:

    ├── mvnw
    ├── mvnw.cmd
    ├── pom.xml
    └── src
    └── main
    ├── java
    │   └── com
    │       └── caco3
    │           └── springbootresources
    │               └── SpringBootResourcesApplication.java
    └── resources
    ├── application.properties
    └── hello
    

上面的示例同时适用于 IDE 和 jar

更深层次的解释

使用抽象资源代替 File
  • 抽象资源的例子有 InputStreamURL
  • 避免使用 File,因为并不总是可以从类路径资源获取它
    • 例如,下面的代码可以在 IDE 中工作:
    public class SpringBootResourcesApplication {
    public static void main(String[] args) throws Exception {
    ClassLoader classLoader = SpringBootResourcesApplication.class.getClassLoader();
    File file = new File(classLoader.getResource("hello").getFile());
    
    
    Files.readAllLines(file.toPath(), StandardCharsets.UTF_8)
    .forEach(System.out::println);
    }
    }
    
    但失败的原因是:
    java.nio.file.NoSuchFileException: file:/home/caco3/IdeaProjects/spring-boot-resources/target/spring-boot-resources-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/hello
    at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
    at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
    at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:116)
    
    当弹簧启动罐运行
  • 如果您使用外部库,并且它要求您提供资源,请尝试找到一种方法将 InputStreamURL传递给它
    • 例如,问题中的 JsonLoader.fromFile可以用 JsonLoader.fromURL方法代替: 它接受 URL
使用框架的工具获取资源:

SpringFramework 支持通过 ClassPathResource访问类路径资源

你可以使用它:

  1. 直接,如从 resources读取文件的示例所示
  2. 间接地:
    1. 使用 @Value:
      @SpringBootApplication
      public class SpringBootResourcesApplication implements ApplicationRunner {
      @Value("classpath:/hello") // Do not use field injection
      private Resource resource;
      
      
      public static void main(String[] args) throws Exception {
      SpringApplication.run(SpringBootResourcesApplication.class, args);
      }
      
      
      @Override
      public void run(ApplicationArguments args) throws Exception {
      try (InputStream inputStream = resource.getInputStream()) {
      String string = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
      System.out.println(string);
      }
      }
      }
      
    2. 使用 ResourceLoader:
      @SpringBootApplication
      public class SpringBootResourcesApplication implements ApplicationRunner {
      @Autowired // do not use field injection
      private ResourceLoader resourceLoader;
      
      
      public static void main(String[] args) throws Exception {
      SpringApplication.run(SpringBootResourcesApplication.class, args);
      }
      
      
      @Override
      public void run(ApplicationArguments args) throws Exception {
      Resource resource = resourceLoader.getResource("/hello");
      try (InputStream inputStream = resource.getInputStream()) {
      String string = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
      System.out.println(string);
      }
      }
      }
      

试试这个:

在 application.properties

app.jsonSchema=classpath:jsonschema.json

在你的物业上:

注意 : 您可以使用任何首选的方式从 application.properties 读取配置。

@Configuration
@ConfigurationProperties(prefix = "app")
public class ConfigProperties {
private Resource jsonSchema;


// standard getters and setters
}

在类中,阅读 Properties Pojo 中的资源:

//Read the Resource and get the Input Stream
try (InputStream inStream = configProperties.getJsonSchema().getInputStream()) {
//From here you can manipulate the Input Stream as desired....
//Map the Input Stream to a Map
ObjectMapper mapper = new ObjectMapper();
Map <String, Object> jsonMap = mapper.readValue(inStream, Map.class);
//Convert the Map to a JSON obj
JSONObject json = new JSONObject(jsonMap);
} catch (Exception e) {
e.printStackTrace();
}

2021最佳方式


读取文件的最简单方法是:

    Resource resource = new ClassPathResource("jsonSchema.json");
FileInputStream file = new FileInputStream(resource.getFile());

您需要清理路径并用空格替换% 20,或者重命名您的目录。

FileNotFoundException: /home/user/Dev/Java/Java%20Programs/SystemRoutines/target/classes/jsonschema.json

只是把我的答案和其他答案加在一起2美分。我正在使用 Spring DefaultResourceLoader来获得 ResourceLoader。然后,SpringFileCopyUtils将资源文件的内容获取到一个字符串中。

import static java.nio.charset.StandardCharsets.UTF_8;


import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UncheckedIOException;


import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.FileCopyUtils;


public class ResourceReader {
public static String readResourceFile(String path) {
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource(path);
return asString(resource);
}


private static String asString(Resource resource) {
try (Reader reader = new InputStreamReader(resource.getInputStream(), UTF_8)) {
return FileCopyUtils.copyToString(reader);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}

下面是使用 ResourceUtils和 Java11Files.readString的解决方案,它负责 UTF-8编码和资源关闭

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.springframework.util.FileCopyUtils.copyToByteArray;
import org.springframework.core.io.ClassPathResource;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;


public  JsonNode getJsonData() throws IOException {
ClassPathResource classPathResource = new
ClassPathResource("assets/data.json");
byte[] byteArray =
copyToByteArray(classPathResource.getInputStream());
return new ObjectMapper() //
.readTree(new String(byteArray, UTF_8));
}

或者更简单

步骤1: 在/src/main/resources/data/test.data 下创建资源文件
步骤2: 在 application.properties/yml中定义值

com.test.package.data=#{new org.springframework.core.io.ClassPathResource("/data/test.data").getFile().getAbsolutePath()}

步骤3: 在代码中获取文件

@Value("${com.test.package.data}")
private String dataFile;


private void readResourceFile() {
Path path = Paths.get(dataFile);
List<String> allLines = Files.readAllLines(path);
}