从 HTML 资源读取时出现 FileNotFoundException 异常
FileNotFoundException exception when reading from a HTML resource
我尝试打开并读取 class 路径中的 HTML 文件。
请在下面的截图中找到目录结构
里面 class SendEmail
class 我想读那个 verification.html
文件。
代码
当使用下面的代码时,它向我抛出一个 java.io.FileNotFoundException
异常:
emailContent = readHTMLFile("../emailTemplate/EmailVerificationTemplate/verification.html");
readHTMLFile
方法如下所示:
public String readHTMLFile(String path) throws IOException {
String emailContent = "";
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
while ((emailContent = bufferedReader.readLine()) != null) {
stringBuilder.append(emailContent);
}
return stringBuilder.toString();
}
但是,当我使用 绝对 路径时,一切正常。
我是 Java 世界的新手。
请帮我解决这个问题。
verification.html
看起来更像是“class 路径资源”而不是文件...
(一个文件非常依赖于环境(例如考虑它的 path/location),而我们打包并随我们的应用程序一起提供的“CPR”可以用已知和固定的(绝对或相对)引用它(class路径)地址。
也不 maven nor gradle(默认情况下)“包含”src/main/java
中除 *.java
文件之外的任何其他内容。所以请将相应的文件(包括structure/packages)移动到src/main/resources
(或相应的src/test/...
)。
当资源最终在class路径中时,由于spring:3.2.2,我们可以这样做:
String emailBody = org.springframework.util.StreamUtils.
copyToString(
new org.springframework.core.io.ClassPathResource(
"/full/package/of/emailTemplate/EmailVerificationTemplate/verification.html")
.getInputStream(),
/* you must know(!), better: */
Charset.forName("UTF-8")
);
(..也 outside/before spring-引导应用程序。)
在 spring 上下文中,Resource
(Classpath
-、ServletContext
-、File
(!)-、URL
- , ...) 也可以被“注入”, 比如:
@Value("classpath:/full/package/...")Resource verificationEmailBody
..而不是调用构造函数。
另请参阅:
- Spring Core#Resources reference doc
Resource
javadoc
- How do I read / convert an InputStream into a String in Java?
- How do I load a resource and use its contents as a string in Spring
当您需要将verification.html
引用为File
时,请确保:
它有一个独特的(绝对(好!)或相对(祝你好运!))地址(在所有目标环境中)!
Java
中的文件和资源
您的文件位于 class 路径 内。这是您的源代码中的一个特殊位置(此处在包 utils.emailTemplate.EmailVerificationTemplate
中)。所以我们称它为 classpath resource 或简称为 resource.
类路径资源
通常那些 resources 注定要与您的代码一起发布,尽管它们实际上不是代码。
在 Maven standard directory layout 中,您可以将它们放在特殊的 src/main/resources
文件夹中,与代码分开。
查找和阅读资源
资源位于相对于class路径的位置,使用classpath:
架构。由于它们是源代码的一部分,您还可以相对于 classes 之一找到它们。
来自您的 SendEmail
class,给定的模板具有相对路径 ../
。因此,您可以将其实例化为 Resource
在 SendEmail
class:
中使用 this.getClass().getResource(Stirng relativePath)
构建 URL
class SendEmail {
private final String relativePath = "../emailTemplate/EmailVerificationTemplate/verification.html";
// build the URL for the resource relative from within your class
public URL getVerificaitonEmailTemplateUrl() {
URL templateResourceUrl = this.getClass().getResource(relativePath);
return templateResourceUrl;
}
// load the resource
public InputStream getVerificaitonEmailTemplateStream() {
InputStream is = this.getClass().getResourceAsStream(relativePath);
return is;
}
}
加载资源作为输入流getResourceAsStream(String name)
使用 class.
内部的相对路径
使用 Spring 的专用扩展 ClassPathResource
的替代方法:
private final String relativePath = "../emailTemplate/EmailVerificationTemplate/verification.html";
public String loadContentAsFile() {
ClassPathResource resource = new ClassPathResource(relativePath);
File file resource.getFile();
String content = new String(Files.readAllBytes(file.toPath()));
return content;
}
public InputStream getContentAsStream() {
ClassPathResource resource = new ClassPathResource(relativePath);
InputStream is resource.getInputStream();
return is;
}
注意:此从文件读取 仅当您的资源在文件系统中时才有效。如果您的资源在 JAR 中则不会:
This implementation returns a File reference for the underlying class path resource, provided that it refers to a file in the file system.
从 ClassPathResource
中读取的更安全、更可靠的方法是 resource.getInputStream()
。
从 InputStream 到 String
要修复您的方法,您只需将 File
相关部分替换为 InputStream
:
public String readHTML(InputStream is) throws IOException {
String emailContent = "";
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
while ((emailContent = bufferedReader.readLine()) != null) {
stringBuilder.append(emailContent);
}
return stringBuilder.toString();
}
或者更简单(参见下面链接的 Baeldung 教程):
String text = new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8)) // choose the encoding to fit
.lines()
.collect(Collectors.joining("\n"));
然后重新使用它从任何流中读取(例如 File
、Resource
、ClassPathResource
,甚至 URL
)。例如:
public String loadTemplate(String relativeResourcePath) throws IOException {
InputStream inputStream = this.getClass().getResourceAsStream(relativeResourcePath)
String text = new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));
return text;
}
另见
我尝试打开并读取 class 路径中的 HTML 文件。
请在下面的截图中找到目录结构
里面 class SendEmail
class 我想读那个 verification.html
文件。
代码
当使用下面的代码时,它向我抛出一个 java.io.FileNotFoundException
异常:
emailContent = readHTMLFile("../emailTemplate/EmailVerificationTemplate/verification.html");
readHTMLFile
方法如下所示:
public String readHTMLFile(String path) throws IOException {
String emailContent = "";
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new FileReader(path));
while ((emailContent = bufferedReader.readLine()) != null) {
stringBuilder.append(emailContent);
}
return stringBuilder.toString();
}
但是,当我使用 绝对 路径时,一切正常。
我是 Java 世界的新手。 请帮我解决这个问题。
verification.html
看起来更像是“class 路径资源”而不是文件... (一个文件非常依赖于环境(例如考虑它的 path/location),而我们打包并随我们的应用程序一起提供的“CPR”可以用已知和固定的(绝对或相对)引用它(class路径)地址。也不 maven nor gradle(默认情况下)“包含”
src/main/java
中除*.java
文件之外的任何其他内容。所以请将相应的文件(包括structure/packages)移动到src/main/resources
(或相应的src/test/...
)。当资源最终在class路径中时,由于spring:3.2.2,我们可以这样做:
String emailBody = org.springframework.util.StreamUtils. copyToString( new org.springframework.core.io.ClassPathResource( "/full/package/of/emailTemplate/EmailVerificationTemplate/verification.html") .getInputStream(), /* you must know(!), better: */ Charset.forName("UTF-8") );
(..也 outside/before spring-引导应用程序。)
在 spring 上下文中,
Resource
(Classpath
-、ServletContext
-、File
(!)-、URL
- , ...) 也可以被“注入”, 比如:@Value("classpath:/full/package/...")Resource verificationEmailBody
..而不是调用构造函数。
另请参阅:
- Spring Core#Resources reference doc
Resource
javadoc- How do I read / convert an InputStream into a String in Java?
- How do I load a resource and use its contents as a string in Spring
当您需要将verification.html
引用为File
时,请确保:
它有一个独特的(绝对(好!)或相对(祝你好运!))地址(在所有目标环境中)!
Java
中的文件和资源您的文件位于 class 路径 内。这是您的源代码中的一个特殊位置(此处在包 utils.emailTemplate.EmailVerificationTemplate
中)。所以我们称它为 classpath resource 或简称为 resource.
类路径资源
通常那些 resources 注定要与您的代码一起发布,尽管它们实际上不是代码。
在 Maven standard directory layout 中,您可以将它们放在特殊的 src/main/resources
文件夹中,与代码分开。
查找和阅读资源
资源位于相对于class路径的位置,使用classpath:
架构。由于它们是源代码的一部分,您还可以相对于 classes 之一找到它们。
来自您的 SendEmail
class,给定的模板具有相对路径 ../
。因此,您可以将其实例化为 Resource
在 SendEmail
class:
this.getClass().getResource(Stirng relativePath)
构建 URL
class SendEmail {
private final String relativePath = "../emailTemplate/EmailVerificationTemplate/verification.html";
// build the URL for the resource relative from within your class
public URL getVerificaitonEmailTemplateUrl() {
URL templateResourceUrl = this.getClass().getResource(relativePath);
return templateResourceUrl;
}
// load the resource
public InputStream getVerificaitonEmailTemplateStream() {
InputStream is = this.getClass().getResourceAsStream(relativePath);
return is;
}
}
加载资源作为输入流getResourceAsStream(String name)
使用 class.
使用 Spring 的专用扩展 ClassPathResource
的替代方法:
private final String relativePath = "../emailTemplate/EmailVerificationTemplate/verification.html";
public String loadContentAsFile() {
ClassPathResource resource = new ClassPathResource(relativePath);
File file resource.getFile();
String content = new String(Files.readAllBytes(file.toPath()));
return content;
}
public InputStream getContentAsStream() {
ClassPathResource resource = new ClassPathResource(relativePath);
InputStream is resource.getInputStream();
return is;
}
注意:此从文件读取 仅当您的资源在文件系统中时才有效。如果您的资源在 JAR 中则不会:
This implementation returns a File reference for the underlying class path resource, provided that it refers to a file in the file system.
从 ClassPathResource
中读取的更安全、更可靠的方法是 resource.getInputStream()
。
从 InputStream 到 String
要修复您的方法,您只需将 File
相关部分替换为 InputStream
:
public String readHTML(InputStream is) throws IOException {
String emailContent = "";
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
while ((emailContent = bufferedReader.readLine()) != null) {
stringBuilder.append(emailContent);
}
return stringBuilder.toString();
}
或者更简单(参见下面链接的 Baeldung 教程):
String text = new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8)) // choose the encoding to fit
.lines()
.collect(Collectors.joining("\n"));
然后重新使用它从任何流中读取(例如 File
、Resource
、ClassPathResource
,甚至 URL
)。例如:
public String loadTemplate(String relativeResourcePath) throws IOException {
InputStream inputStream = this.getClass().getResourceAsStream(relativeResourcePath)
String text = new BufferedReader(
new InputStreamReader(inputStream, StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));
return text;
}