繁体   English   中英

在 Spring Boot 中从 resources 文件夹中读取文件

[英]Read file from resources folder in Spring Boot

我正在使用 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);

这是文件的位置。

在此处输入图像描述

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

在此处输入图像描述

但是当我运行代码时,出现以下错误。

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

我的代码做错了什么?

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

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

在此处输入图片说明

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 运行它的正确方法。

非常简短的回答:您正在类加载器的类而不是目标类的范围内寻找资源。 这应该有效:

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

此外,这可能有助于阅读:

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

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

2020 年更新

最重要的是,如果您想将资源文件作为字符串读取,例如在您的测试中,您可以使用这些静态 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");

如果您在 Resources 文件夹下有例如 config 文件夹,我试过这个类工作得很好,希望有用

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

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

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

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

2021年最好的方式


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

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

在此处查看我的答案: 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()

参考: http : //frugalisminds.com/spring/load-file-classpath-spring-boot/正如前面的答案中已经提到的,不要使用 ResourceUtils 它在部署 JAR 后不起作用,这也适用于 IDE部署后

如何可靠地获取资源

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

  1. 想办法传递抽象资源,例如InputStream , URL而不是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);
        }
    }
}

上面的示例适用于 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)
    当 Spring 启动 jar 运行时
  • 如果您使用外部库,并且它要求您提供资源,请尝试找到一种方法将其传递给InputStreamURL
    • 例如,问题中的JsonLoader.fromFile可以替换为JsonLoader.fromURL方法:它接受URL
使用框架的工具来获取资源:

Spring 框架支持通过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); } } }
      • 另请参阅答案

在资源中创建 json 文件夹作为子文件夹,然后在文件夹中添加 json 文件,然后您可以使用以下代码: 在此处输入图片说明

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

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

这适用于 Docker。

陷入同样的​​问题,这对我有帮助

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

下面是我的工作代码。

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));

希望对大家有所帮助!

将资源目录中的类路径中的资源解析为字符串的最简单方法是以下一行。

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

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

此方法使用StreamUtils实用程序并以简洁紧凑的方式将文件作为输入流流式传输到字符串中。

如果您希望文件作为字节数组,您可以使用基本的 Java 文件 I/O 库:

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

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

这是我的解决方案。 可能会帮助某人;

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

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

对我来说,这个错误有两个修复。

  1. 名为 SAMPLE.XML 的 Xml 文件在部署到 aws ec2 时甚至导致以下解决方案失败。 修复方法是将其重命名为 new_sample.xml 并应用下面给出的解决方案。
  2. 解决方法https://medium.com/@jonathan.henrique.smtp/reading-files-in-resource-path-from-jar-artifact-459ce00d2130

我使用 Spring boot 作为 jar 并部署到 aws ec2 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);
      }
  }
}

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());

只是将我的解决方案与所有其他答案一起添加为另外 2 美分。 我正在使用 Spring DefaultResourceLoader来获取ResourceLoader 然后Spring FileCopyUtils将资源文件的内容转为字符串。

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和 Java 11 Files.readString的解决方案,它负责 UTF-8 编码和资源关闭

import org.json.JSONObject;
import org.springframework.util.ResourceUtils;
 
public JSONObject getJsonData() throws IOException {
        //file path : src/main/resources/assets/data.json
        File file = ResourceUtils.getFile("classpath:assets/data.json");
        String data = Files.readString(file.toPath());
        return new JSONObject(data);
 }

但是在 OpenShift 上部署应用程序后,资源无法访问。 所以正确的解决方案是

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));
}

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

Java 程序之间有空格。重命名文件夹名称应该可以使它工作

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

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

我有同样的问题,因为我只需要获取文件路径来发送到文件输入流,我就这样做了。

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

使用 Spring ResourceUtils.getFile()你不必注意绝对路径:)

 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;
}

尝试这个:

在 application.properties

app.jsonSchema=classpath:jsonschema.json

在您的属性 pojo 上:

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

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

// standard getters and setters
}

在您的 class 中,从 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();
    }

您需要清理路径并将 %20 替换为空格,或重命名您的目录。 然后它应该工作。

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

如今,在 2023 年,Java 位用户应该能够更轻松地读取类路径文件。 使用简单的指令,例如new File("classpath:path-to-file")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM