簡體   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