本文的主要内容是介绍几种常用的文件打开方式,可以解决实际项目开发中很多的文件打开场景
- 基于环境变量user.dir找到文件位置
- 基于ClassLoader找到文件的位置
- 在IDEA中打开文件
- 在Tomcat中打开文件
- 基于Spring找到文件的位置
- 基于Maven打开resources目录下的文件
打开文件的一般思路
- 确定文件位置
- 使用java.io.File打开文件,使用InputStream、Reader载入文件流,或者OutputStream、Writer写出文件流
内容导览
user.dir
- dir系统属性是 JVM 启动的时候设置的,通常是 Java 虚拟机的调用目录,即执行 java 字节码所在的目录。
- 如果存在包,那么“./”为包的上一级目录。如果是jar包,则“./”为当前jar包所在目录。
- 对于Tomcat/jboss 容器,dir 是 %web容器目录%/bin/ 目录,因为这个目录就是我们启动 web 容器的地方。
- 在Eclipse和IDEA,getProperty("user.dir")为工程的根目录
public class OpenFileDemo {
public static void main(String[] args) throws Exception {
String userDir = System.getProperty("user.dir");
System.out.println("当前程序(不含包名)运行所在目录: " + userDir); //D:\A03-Program\A-Programming\IDEA\boot
}
}
在Tomcat容器中的user.dir为bin目录
ClassLoader
- 读取字节码路径下的文件
- 类名.getResource(“资源名称”),返回URL
- 绝对路径以 / 开头,从classpath 或 jar 包根目录下开始搜索;
- 相对路径是相对当前class 所在的目录,允许使用 .. 或 . 来定位文件。
- 类名.getClassLoader().getResourceAsStream(),返回InputStream。只能使用绝对路径,而且不用以 / 开头。
- 类名.getResource(“资源名称”),返回URL
- 这两种方式读取资源文件,不会依赖于dir,也不会依赖于具体部署的环境,是推荐的做法
- ClassLoader 不能读取太大的文件,它适合读取项目的配置文件
ClassLoader加载字节码所在目录下的文件
获取当前字节码文件的绝对路径
import java.io.File;
import java.net.URL;
public class OpenFileDemo {
public static void main(String[] args) throws Exception {
//在静态方法中使用".class.getClassLoader()"获取类加载器
String path = OpenFileDemo.class.getClassLoader().getResource("").getPath();//注意getResource("")里面是空字符串
System.out.println(path); //输出:/D:/A03-Program/A-Programming/IDEA/boot/target/classes/
//File file = new File(path + "aa.txt");
new OpenFileDemo().test01();
}
public void test01() {
//在普通方法中使用"this.getClass().getClassLoader()"获取类加载器
URL resource = this.getClass().getClassLoader().getResource(""); //注意getResource("")里面是空字符串
String path = resource.getPath();
System.out.println(path);
String filePath = URLDecoder.decode(path, "UTF-8"); //如果路径中带有中文会被URLEncoder,因此这里需要解码
String fileName = "aa.txt";
File file = new File(filePath + fileName);
System.out.println(file.exists()); //true
}
}
IDEA
IDEA默认从项目根目录查找文件
public static void readFile() throws Exception {
//IDEA中还是以工程的根目录为相对文件的根目录
//在项目的根目录下建立一个文件夹file,在其文件夹下建立文件hello.txt
File file = new File("file/hello.txt");
System.out.println("文件的绝对路径:" + file.getAbsolutePath());
BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
byte[] buffer = new byte[1024];
int read = in.read(buffer);
System.out.println("文件内容:" + new String(buffer, 0, read, StandardCharsets.UTF_8));
//Output:
//文件的绝对路径:D:\E-DataProject\JSE\file\hello.txt
//文件内容:This is a test text.
}
Tomcat
获取Tomcat的运行目录
- new File(".").getAbsolutePath() 当前文件所在目录
- getSession().getServletContext().getRealPath("") 项目所在目录
- getProperty("catalina.home") Tomcat根目录
- getProperty("user.dir") Tomcat的bin目录,因为Tomcat是从改个目录启动的
<%@ page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %>
<%@ page import="java.io.File" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>PN</title>
</head>
<body>
<%
File file01 = new File(".");
pageContext.setAttribute("file01", file01.getAbsolutePath());
File file02 = new File("./");
pageContext.setAttribute("file02", file02.getAbsolutePath());
File file03 = new File("../");
pageContext.setAttribute("file03", file03.getAbsolutePath());
pageContext.setAttribute("requestServerletPath", request.getSession().getServletContext().getRealPath(""));
%>
<!-- JSP表达式 -->
catalina.home: <%= System.getProperty("catalina.home") %> <br/>
user.dir: <%= System.getProperty("user.dir") %> <br/>
requestServerletPath: ${requestServerletPath} <br/>
file01: ${file01} <br/>
file02: ${file02} <br/>
file03: ${file03} <br/>
<!--
Output
catalina.home: F:\A04-Storage\PN-Tomcat\apache-tomcat-9.0.31-windows-x64
user.dir: F:\A04-Storage\PN-Tomcat\apache-tomcat-9.0.31-windows-x64\bin
requestServerletPath: F:\A04-Storage\PN-Tomcat\apache-tomcat-9.0.31-windows-x64\webapps/pn
file01: F:\A04-Storage\PN-Tomcat\apache-tomcat-9.0.31-windows-x64\bin\.
file02: F:\A04-Storage\PN-Tomcat\apache-tomcat-9.0.31-windows-x64\bin\.
file03: F:\A04-Storage\PN-Tomcat\apache-tomcat-9.0.31-windows-x64\bin\..
-->
</body>
</html>
Spring加载文件
import org.springframework.core.io.ClassPathResource;
//加载resources/static/template目录下的文件
ClassPathResource resource = new ClassPathResource("static/template/report_template.xlsx");
File file = resource.getFile();
import org.springframework.util.ResourceUtils;
File rootPath = new File(ResourceUtils.getURL("classpath:").getPath()); //SpringBoot项目获取根目录的方式
File templatePath = new File(rootPath.getAbsolutePath(),"/excel_template/userInfo.xlsx"); //加载resources/excel_template目录下的文件
读取resources下的文件
import org.springframework.core.io.ClassPathResource;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
public class OpenFileDemo {
public static void main(String[] args) throws Exception {
OpenFileDemo openFileDemo = new OpenFileDemo();
openFileDemo.method01();
openFileDemo.method02();
openFileDemo.method03();
openFileDemo.method04();
openFileDemo.method05();
openFileDemo.method06();
openFileDemo.method07();
}
/**
* getPath(): 直接通过文件名来获取路径
* 使用单元测试@Test,获取的是Junit的jar包所在位置
*/
public void method01() {
URL resource = this.getClass().getClassLoader().getResource(""); //注意getResource("")里面是空字符串
String path = resource.getPath();
String filePath = URLDecoder.decode(path, StandardCharsets.UTF_8); //如果路径中带有中文会被URLEncoder,因此这里需要解码
//打开resources/data/aa.txt下的文件
File file = new File(filePath + "data/aa.txt");
System.out.println(filePath + ": " +file.exists());
}
public void method02() {
//打开resources/data/aa.txt下的文件
URL resource = this.getClass().getClassLoader().getResource("data/aa.txt");
String path = resource.getPath();
String filePath = URLDecoder.decode(path, StandardCharsets.UTF_8); //如果路径中带有中文会被URLEncoder,因此这里需要解码
File file = new File(filePath);
System.out.println(filePath + ": " +file.exists());
}
/**
* getFile():等价于getPath
* 如果是文件路径的话getFile和getPath效果是一样的,如果是URL路径的话getPath是带有参数的路径。
*/
public void method03() {
//打开resources/data/aa.txt下的文件
URL resource = this.getClass().getClassLoader().getResource("data/aa.txt");
String path = resource.getFile();
String filePath = URLDecoder.decode(path, StandardCharsets.UTF_8); //如果路径中带有中文会被URLEncoder,因此这里需要解码
File file = new File(filePath);
System.out.println(filePath + ": " +file.exists());
}
/**
* getResourceAsStream: 直接获取到InputStream
* 基于Spring
*/
public void method04() throws Exception {
//打开resources/data/aa.txt下的文件
InputStream in = this.getClass().getClassLoader().getResourceAsStream("data/aa.txt");
BufferedInputStream is = new BufferedInputStream(in);
System.out.println(new String(is.readAllBytes(), StandardCharsets.UTF_8));
}
/**
* 通过ClassPathResource获取文件流
*/
public void method05() throws Exception {
//打开resources/data/aa.txt下的文件
ClassPathResource classPathResource = new ClassPathResource("data/aa.txt");
InputStream in = classPathResource.getInputStream();
BufferedInputStream is = new BufferedInputStream(in);
System.out.println(new String(is.readAllBytes(), StandardCharsets.UTF_8));
}
/**
* 获取项目的绝对路径,不能用于服务器获取
* 不要使用!!!
*/
public void method06() throws Exception {
String projectPath = System.getProperty("user.dir");
String filePath = projectPath + "/src/main/resources/data/aa.txt";
File file = new File(filePath);
System.out.println(filePath + ": " + file.exists());
}
/**
* 获取当前字节码文件的绝对路径
* 不能用于服务器获取
*/
public void method07() throws Exception {
File dir = new File(".");
File canonicalFile = dir.getCanonicalFile();
String absolutePath = dir.getAbsolutePath();
System.out.println(absolutePath);
}
}
Name:
Email:
Link: