在 docker 容器中使用 java 访问类路径中的 JSON 文件时面临 FileNotFoundException(SprintBootApplication)

Posted

技术标签:

【中文标题】在 docker 容器中使用 java 访问类路径中的 JSON 文件时面临 FileNotFoundException(SprintBootApplication)【英文标题】:Facing FileNotFoundException while accessing JSON File in classpath using java in docker containers(SprintBootApplication) 【发布时间】:2017-02-15 03:03:47 【问题描述】:

我在使用 docker 容器加载位于 Java jar 的类路径中的 JSON 文件时遇到 FileNotFoundException,它是一个 Spring-Boot 应用程序。此 JSON 文件在资源文件夹中可用。我能够在 ./target/classes/ 路径下的 docker 中看到 JSON 文件。

Resource resource = resourceLoader.getResource("classpath:folderNm/file.json");
HashMap<String, String> headerMapping = (HashMap<String, String>) parser.parse(new FileReader(resource.getFile().getAbsolutePath()));

但我得到了这个例外:

java.io.FileNotFoundException: class path resource [folderNm/file.json] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/app.jar!/folderNm/file.json

我试过了

-> resource.getFile().getPath(); -> resource.getFile().getCanonicalPath(); -> "./target/classes/folderName/fileName"(硬编码文件路径位置) -> "/app.jar!/folderNm/file.json"(硬编码的 FilePath 位置)

InputStream inputStream = getClass().getResourceAsStream("xyz.json");
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
            StringBuilder responseStrBuilder = new StringBuilder();
            String inputStr;
            while ((inputStr = br.readLine()) != null)
                responseStrBuilder.append(inputStr);

上述方法均未运行。请提出解决此问题的方法。

【问题讨论】:

您是否尝试过 Resource resource = resourceLoader.getResource("classpath:/folderNm/file.json");带有前导斜杠? 我也遇到过类似的问题。实际上,对我来说,最好在构建 docker 映像时简单地添加文件,然后简单地使用路径访问它。我不确定你是否可以反过来做。你需要记住,下面的 spring boot 使用的是 tomcat/jetty/undertow 嵌入的。 @AntonBelev,我也尝试过使用前导 /,但没有奏效。 @gmaslowski,您能否说明一下如何从 docker 映像中读取文件? 以下代码对我有用。首先,我在类路径中使用 maven 添加了 JSON 文件。第二个在java中我使用了下面的代码 String parsedJSONString = ""; ClassPathResource cpr = new ClassPathResource(filePath);字节[] bdata = null;试试 bdata = FileCopyUtils.copyToByteArray(cpr.getInputStream()); 捕捉(异常 e1) e1.printStackTrace(); parsedJSONString = new String(bdata, StandardCharsets.UTF_8); 【参考方案1】:

假设在 maven 结构中(您使用的是 maven,对吗?)您的文件位于 src/main/resources/folderName/file.json,那么您传递给 getResourceAsStream 的路径应该是 /folderName/file.json

其实一切都在javadocs中解释过:

在委托之前,绝对资源名称由 使用此算法给定资源名称:

如果名称以 '/' ('\u002f') 开头,则绝对名称 资源是名称中“/”之后的部分。 否则, 绝对名称的格式如下:modified_pa​​ckage_name/name

modified_pa​​ckage_name 是这个对象的包名 用“/”代替“。” ('\u002e')。

基本上,如果您跳过前面的“/”,它会在您的类的包中查找 folderName。以下代码对我来说很好:

    InputStream inputStream = StackTest.class.getResourceAsStream("/folderName/file.json");
    BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
    StringBuilder responseStrBuilder = new StringBuilder();
    String inputStr;
    while ((inputStr = br.readLine()) != null)
        responseStrBuilder.append(inputStr);
    System.out.println(responseStrBuilder.toString());

假设我的 file.json 在 src/main/resources/folderName 中。我认为这与 docker 无关。 顺便说一句,我认为您可以使用 Apache Commons IOUtils.toString 来帮助将 InputStream 转换为字符串。

【讨论】:

我的问题是前面的“/”花了这么多时间,谢谢你的解释。【参考方案2】:

创建文件:

src/main/resources/firebase/your_account_json.json

加载输入流:

String path = "/firebase/your_account_json.json";
InputStream in = this.getClass().getResourceAsStream(path);
FirebaseOptions options = new FirebaseOptions.Builder().setCredentials(GoogleCredentials.fromStream(in))
      .setDatabaseUrl("https://your-project.firebaseio.com")
      .setStorageBucket("your-project.appspot.com")
      .build();

【讨论】:

以上是关于在 docker 容器中使用 java 访问类路径中的 JSON 文件时面临 FileNotFoundException(SprintBootApplication)的主要内容,如果未能解决你的问题,请参考以下文章

Java应用在docker环境配置容器健康检查

从 Docker 容器中的 Java 应用程序访问 Windows 10 中的文件夹

Docker部署Rstudio Server【三】:docker容器管理初步

docker映射网络路径

尝试从 docker 容器中使用 SSH 密钥 [重复]

2021-10-27