在Java开发中,往往我们需要读取配置文件,或者读写系统文件,读写下载文件等等操作,是不是有时遇到提示系统找不到指定路径的文件的错误,
由此,我今天整理一下,希望以后能避免这种错误的出现。
面对路径问题,我们总得问问自己,什么是绝对路径,什么是相对路径,相对路径又是相对于谁,以谁作为参考点?
所谓的绝对路径,就是文件在整个文件系统的全路径,如在Windows下,D:\JAVA\MyEclipse\MyEclipse 10 这个文件夹 或者 D:\JAVA\MyEclipse\MyEclipse 10\myeclipse.exe
这个文件,都是以全路径名的形式出现的。只是在Java代码中,\ 是必须转义的,所以我们写绝对路径时,总会D:\\JAVA\MyEclipse\\MyEclipse 10\\myeclipse.exe。
如代码中:
File file04 = new File("C:\\test1\\test101\\SeProjectFileDemo04.txt");
File file05 = new File(dirAbsPath05,"SeProjectFileDemo05.txt");
这两种都是绝对路径的写法,其中前者中C:\\test1\\test101\\的目录必须事先已经存在者两个目录,
后者dirAbsPath05也必须是已经创建好的目录,如代码中就
File dir05 = new File("C:\\test2\\test201");
if(!dir05.exists()) dir05.mkdirs();
创建好这两个目录啦。
那什么什么是相对路径呢?
所谓的相对路径,就是相对某个目录的情况下,某个资源文件的短名称,这其中就涉及到参考谁的问题了。
如:如果我说,以后你们写相对路径,都是以 D:\\JAVA\MyEclipse\\MyEclipse 10 这个目录为参考点 ,那么
File file = new File("myeclipse.exe"); 中的"myeclipse.exe" 就是一个相对路径的写法。
那么在开发Java程序的时候,写相对路径时,这个参考点会是那么目录呢?这个等看完相应的代码就知道了。
首先说的是JavaSe的应用程序工程:
首先我创建了一个JavaApplication工程,工程根目录是:D:\JAVA\MyEclipse10\ThreeDays ,大家暂时记住这个路径
然后我新建一个普通Java类 :ThreeDays/src/three/day/filepath/FilePathDemo01.java
代码如下:
package three.day.filepath;
import java.io.File;
import java.io.IOException;
public class FilePathDemo01 {
public static void main(String[] args) throws IOException {
//-------------------------------使用相对路径----------------------------//
File file01 = new File("SeProjectFileDemo01.txt");
if(!file01.exists()) file01.createNewFile();
String fileAbsPath01 = file01.getAbsolutePath();
System.out.println(fileAbsPath01);
File file02 = new File("/", "SeProjectFileDemo02.txt");
if(!file02.exists()) file02.createNewFile();
String fileAbsPath02 = file02.getAbsolutePath();
System.out.println(fileAbsPath02);
File file03 = new File("dir", "SeProjectFileDemo03.txt");
if(!file03.exists()) file03.createNewFile();
String fileAbsPath03 = file03.getAbsolutePath();
System.out.println(fileAbsPath03);
//--------------------------------使用绝对路径----------------------------//
//创建的文件不再工程目录下
//自己手动在C盘下建好test1和test101文件夹
File file04 = new File("C:\\test1\\test101\\SeProjectFileDemo04.txt");
if(!file04.exists()){
file04.createNewFile();
}
String fileAbsPath04 = file04.getAbsolutePath();
System.out.println(fileAbsPath04);
//使用代码创建目录
File dir05 = new File("C:\\test2\\test201");
if(!dir05.exists()) dir05.mkdirs();
String dirAbsPath05 = dir05.getAbsolutePath();
System.out.println(dirAbsPath05);
//在创建好的目录创建文件
File file05 = new File(dirAbsPath05,"SeProjectFileDemo05.txt");
if(!file05.exists()){
file05.createNewFile();
}
String fileAbsPath05 = file05.getAbsolutePath();
System.out.println(fileAbsPath05);
}
}
运行效果为:
D:\JAVA\MyEclipse10\ThreeDays\SeProjectFileDemo01.txt
D:\SeProjectFileDemo02.txt
D:\JAVA\MyEclipse10\ThreeDays\dir\SeProjectFileDemo03.txt
C:\test1\test101\SeProjectFileDemo04.txt
C:\test2\test201
C:\test2\test201\SeProjectFileDemo05.txt
涉及绝对的代码,没什么好说的了,都写死的了。但是相对路径话,我们通过观察,可以总结:
在JavaSe工程中,相对路径的参考点就是 工程的根目录,我代码工程目录一开始就提到是
D:\JAVA\MyEclipse10\ThreeDays
所以,运行效果的第一和第三行,就很正常不过了。
可是,有没有发现第二行的输出结果,竟然是D:\SeProjectFileDemo02.txt,我们的工程根目录不是D:\JAVA\MyEclipse10\ThreeDays吗?
看看代码写法:File file02 = new File("/", "SeProjectFileDemo02.txt");
由此,可以看出,当父目录是 / 时,就代表工程根目录的根目录咯。
接下来,再看看通过类装载器获取资源文件时,相对路径的参考点又是那个目录呢?
工程还是原来的工程,工程根目录:D:\JAVA\MyEclipse10\ThreeDays
类是:/ThreeDays/src/three/day/filepath/FilePathDemo02.java
其中,代码是通过类装载器去读取资源文件的。
配置文件dbcfg.properties的内容就三行数据:
url=jdbc:mysql://localhost:3306/test
user=root
password=916520
package three.day.filepath;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class FilePathDemo02 {
public static void main(String[] args) throws IOException {/**
* 1、一开始,假设相对目录的参考点 是 工程的根目录
* 1)然后将dbcfg.properties配置文件放在工程根目录下,可是运行出错,说明通过类装载器去读取相对路径文件时,相对路径的参考点不是工程根目录
* 2、假设,工程下的bin目录是相对路径的参考点,将dbcfg.properties配置文件放在bin目录下,运行,果真可以,假设成立
* 3、假设,如果dbcfg.properties配置文件放在bin目录下的three/day/目录下,相对路径还是这样写"dbcfg.properties",
* ClassLoader会不会帮我深度搜索呢?运行,报错,证明ClassLoader不会帮我们搜索,只好改成three/day/dbcfg.properties
*/// three/day/dbcfg.properties
// three/day/filepath/dbcfg.properties
// dbcfg.properties
loaderFindFile("dbcfg.properties");
}
private static void loaderFindFile(String relativePath) throws IOException {
ClassLoader loader = FilePathDemo02.class.getClassLoader();
System.out.println(loader);
InputStream is = loader.getResourceAsStream(relativePath);
Properties props = new Properties();
props.load(is);
String url = props.getProperty("url");
String user = props.getProperty("user");
String password = props.getProperty("password");
System.out.println(url);
System.out.println(user);
System.out.println(password);
}
}
小细节:我在代码中说,将dbcfg.properties配置文件放在bin目录下,其实我只是把配置文件放置在 src 目录下即可。
因为,继承开发环境,实际src中参与编译的文件生成的文件 放置在对应的bin目录下。
另外,补充一点,修改源代码成这样:
package three.day.filepath;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Properties;
public class FilePathDemo03 {
public static void main(String[] args) throws IOException, URISyntaxException {
loaderFindFile("dbcfg.properties");
}
private static void loaderFindFile(String relativePath) throws IOException, URISyntaxException {
ClassLoader loader = FilePathDemo03.class.getClassLoader();
URL u = loader.getResource(relativePath);
File file = new File(u.getPath());
System.out.println(u.getPath());
// File file = new File(u.toURI());
// System.out.println(u.toURI().getPath());
FileInputStream fis = new FileInputStream(file);
Properties props = new Properties();
props.load(fis);
String url = props.getProperty("url");
String user = props.getProperty("user");
String password = props.getProperty("password");
System.out.println(url);
System.out.println(user);
System.out.println(password);
}
}
为什么要这样改呢?
原来是:
ClassLoader loader = FilePathDemo02.class.getClassLoader();
InputStream is = loader.getResourceAsStream(relativePath);改成:
ClassLoader loader = FilePathDemo03.class.getClassLoader();
URL u = loader.getResource(relativePath);
File file = new File(u.getPath());
FileInputStream fis = new FileInputStream(file);
为什么需要这样的改变呢?
第一种的做法,是通过类装载器装载配置文件,类装载器只会读取一遍配置文件,之后配置文件的内容一致驻留在内存中,
可是如果我们是做web开发的话,web服务器启动了,你要修改配置文件的里面,如果使用第一种方式的话,你想想,
会不会立刻修改,立刻生效呢?不会!除非你把web服务重启,或者重新部署web应用。可是一旦产品上线,一般不允许
这种操作的。所以你必须使用第二中写法了,这样,还是读取文件,每次都会来读取配置文件,这样,你没修改了配置文件
就会立刻生效,因为再次读取文件,当然也就是更新后的内容了。
下面再谈谈开发web应用的相对路径问题,内容太多了,还是写在 谈谈Java开发中遇到的资源文件路径问题(二)吧!