【问题标题】:Read file from resources folder in Spring Boot从 Spring Boot 中的资源文件夹中读取文件
【发布时间】:2017-11-08 00:37:40
【问题描述】:

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

我在代码中做错了什么?

【问题讨论】:

  • 你能试试这个吗? ClassLoader classLoader = getClass().getClassLoader(); JsonNode mySchema = JsonLoader.getJson(classLoader.getResourceAsStream("jsonschema.json"));

标签: java spring spring-boot json-schema-validator


【解决方案1】:

2021 最佳方式


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

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

【讨论】:

  • 这在可执行 jar 中不起作用。相反,我们可以使用InputStream inputStream = resource.getInputStream();
【解决方案2】:

试试这个:

在 application.properties 中

app.jsonSchema=classpath:jsonschema.json

在您的属性 pojo 上:

注意:您可以使用任何首选方式从 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();
    }

【讨论】:

    【解决方案3】:

    如何可靠地获取资源

    要可靠地从 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);
            }
        }
    }
    

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

    Spring Framework 允许通过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);
                }
            }
        }
        

    【讨论】:

    • ClassPathResource 在 Fat jar 中不起作用
    • 能否请您提供更多详细信息,也许,您可以在它不起作用的地方发布一个简单的应用程序?
    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

        以下适用于 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());
        

        【讨论】:

          【解决方案7】:

          如果您在项目中使用 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>
          

          【讨论】:

            【解决方案8】:

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

            参考了这个link

            【讨论】:

              【解决方案9】:

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

              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 年更新

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

              【讨论】:

              • getClass().getResource("jsonschema.json") 返回null。我还尝试了ClassPathResource res = new ClassPathResource("jsonschema.json"),它只返回jsonschema.json。这与我使用 Spring Boot 有关吗?
              • @g3blv 关于getClass().getResource("jsonschema.json") 返回null 我可以参考这个话题stackoverflow.com/questions/26328040/…。最重要的是尝试重建您的项目。反馈将不胜感激。
              • @g3blv 我提供了答案的更新,请检查
              • @povisenko 如果is 为空,我建议您抛出异常。这意味着您要查找的文件/资源​​不存在。
              • 完整答案。适用于 IDE 和 jar。谢谢。
              【解决方案10】:

              如果您使用springjackson(大多数大型应用程序都会使用),那么请使用简单的oneliner:

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

              【讨论】:

                【解决方案11】:

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

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

                【讨论】:

                  【解决方案12】:

                  遇到同样的问题,这对我有帮助

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

                  【讨论】:

                  【解决方案13】:

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

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

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

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

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

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

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

                  【讨论】:

                    【解决方案14】:

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

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

                    【讨论】:

                      【解决方案15】:

                      下面是我的工作代码。

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

                      希望对你有所帮助!

                      【讨论】:

                        【解决方案16】:

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

                        感谢 Lokesh Gupta 撰写的精彩页面:Blog

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

                        回答一些关于 cmets 的问题:

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

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

                        【讨论】:

                        • 感谢约翰添加此内容。这很有效,而且肯定是使用 ResourceUtil 的更好方法。
                        • @Athar 很高兴我能提供帮助。
                        • 这只有在您尝试从 IDE 运行应用程序时才有效,但是当您运行 jar 时它不会为您找到该文件。
                        • 同意 Hassan,如果从 jar 运行应用程序,我们应该改用 new ClassPathResource("filename").getInputStream()Detail
                        • 同意哈桑。作为警告,ResourceUtils Javadoc 清楚该类主要供内部使用。检查以及stackoverflow.com/questions/25869428/…
                        【解决方案17】:

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

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

                        【讨论】:

                          【解决方案18】:

                          在这里查看我的答案: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 以及部署后起作用

                          【讨论】:

                          • 哪种解决方案?我在 PROD 中测试了它和它,不确定,你必须面临其他问题。
                          【解决方案19】:

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

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

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

                          【讨论】:

                            【解决方案20】:

                            如果您在 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);
                            

                            【讨论】:

                            • 我试过你的解决方案,它可以在 IDE 中运行,但是当你制作 spring jar 输入流时会有所帮助。
                            【解决方案21】:

                            在资源中创建 json 文件夹作为子文件夹,然后在文件夹中添加 json 文件,然后您可以使用此代码:

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

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

                            这适用于 Docker。

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 2019-10-16
                              • 1970-01-01
                              • 2018-05-28
                              • 2020-03-01
                              • 1970-01-01
                              • 2019-04-15
                              • 2018-11-12
                              • 1970-01-01
                              相关资源
                              最近更新 更多