目录
1. 框架中加载配置文件的方式的概述
-
方式1: 通过Properties + IO
-
方式2: 通过ServletContext + IO
-
方式3: 通过类加载器
-
类名.class.getClassLoader().getResourceAsStream("");
-
类名.class.getResourceAsStream("");
-
2. 通过IO流结合Properties加载配置文件
2.1 Properties类概述
-
class Properties extends Hashtable<Object,Object>
Properties 类本质就是一个Map集合, 但是她在Map集合的基础上进行了功能扩展, 那就是该集合可以和IO流结合使用, 能通过IO将键值对存入硬盘的文件中, 也能通过IO从硬盘文件中将键值对加载进来.
该集合没有泛型. -
Properties类的特点:
Properties可以保存在流中或从流中加载.
每个键及其对应的值都是一个字符串.
是Hashtable的子类,说明是一个Map集合. -
Properties类的构造: 常用她的无参构造. public Properties();
-
Properties类的常用成员方法:
-
Object setProperty(String key,String value):该集合的添加功能
-
添加功能源码解析
class Hashtable<K, V> { public V put(K key, V value) { // ... } } class Properties extends Hashtable { public V setProperty(String key, String value) { return put(key, value); } }
可见, setProperty(x,y)其实是调用了父类的put(x,y)方法,并且限定了能传入实参的类型。
-
-
String getProperty(String key):根据键获取值
-
Set<String> stringPropertyNames():获取键的集合
-
void load(Reader reader/InputStream inStream):把文件中的数据读取到Properties集合中
-
注意, 文件中的数据必须是键值对形式, 例如:
# config.properties className=java.util.ArrayList key02=value02 key03=value03
-
-
void store(Writer writer,String comments): 把Properties集合中的数据储存到文件中
- 注意: 第二个参数是对属性列表的描述,不想描述就写null.
-
2.2 Properties作为Map集合使用
public static void main(String[] args) {
Properties properties = new Properties();
properties.put("张三", 20);
properties.put("李四", 21);
properties.put("王五", 22);
Set<Object> keySet = properties.keySet();
for (Object key : keySet) {
Object value = properties.get(key);
System.out.println(key + "\t" + value);
}
}
2.3 Properties的特殊功能
public static void main(String[] args) {
Properties properties = new Properties();
properties.setProperty("张三", "男");
properties.setProperty("李四", "女");
properties.setProperty("王五", "未知");
Set<String> keySet = properties.stringPropertyNames();
for (String key : keySet) {
String value = properties.getProperty(key);
System.out.println(key + "\t" + value);
}
}
2.4 Properties和IO结合使用
- Properties和IO结合使用, 主要用来读写文件. 一般用来读取配置文件.
package cn.king.demo01;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Set;
/**
* Properties 类等效于一个 hashMap,里面装的元素是键值对,
* 但是他的 hashMap 的基础上扩展了功能:
* 能将键值对存入硬盘的文件中,并可以从硬盘文件中将键值对加载进来.
*/
public class Demo01 {
public static void main(String[] args) throws Exception {
// 加载 config.properties 文件
InputStream in = new FileInputStream("config.properties");
Properties properties = new Properties();
// 将输入流中的文件装载进Properties集合中
properties.load(in);
in.close();
// 获取 config.properties 文件中键为"className"的值
// className = java.util.ArrayList
String className = properties.getProperty("className");
// 使用反射创建对象
ArrayList list = (ArrayList) Class.forName(className).newInstance();
// 遍历Properties集合.
Set<String> keySet = properties.stringPropertyNames();
for (String key : keySet) {
String value = properties.getProperty(key);
System.out.println(value);
}
}
}
package cn.king.demo01;
import java.io.*;
import java.util.Properties;
import java.util.Set;
/**
* 需求:
* 已知文件user.txt中的数据是键值对形式,但是不知道内容,
* 请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其值为100
* <p>
* 分析:
* a、把文件中的数据加载到集合中
* b、遍历集合,获得每一个键
* c、判断键key是否有“lisi”,如果有就改变其值value为“100”
* d、把集合中的数据重新存储到文件中
*/
public class Demo03 {
public static void main(String[] args) throws IOException {
//把文件中的数据加载到集合
Properties prop = new Properties();
Reader reader = new FileReader("user.txt");
prop.load(reader);
reader.close();
//遍历集合,得到每一个键
Set<String> set = prop.stringPropertyNames();
for (String key : set) {
//判断是否有“lisi”,有就改值
if ("lisi".equals(key)) {
prop.setProperty(key, "100");
break;
}
}
//集合中的数据重新存入文件
Writer writer = new FileWriter("user.txt");
prop.store(writer, null);
writer.close();
}
}
3. 通过ServletContext对象的获取项目中的任意文件的绝对路径
- 项目结构
package cn.king.web.servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(name = "AServlet", urlPatterns = {"/AServlet"})
public class AServlet extends HttpServlet {
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
/*
* 获取ServletContext对象.
*
* 该对象的一个功能是能获取本项目中任意文件的真实路径,
* 真实路径就是发布到服务器上后的绝对路径.
*/
ServletContext application = this.getServletContext();
// "/"代表web文件夹下. 下面代表获取web文件夹下的a.txt文件的真实路径
String realPath1 = application.getRealPath("/a.txt");
System.out.println("a.txt的绝对路径是: " + realPath1);
// 下面代表获取web文件夹下的WEB-INF文件夹下的b.txt文件的真实路径
String realPath2 = application.getRealPath("/WEB-INF/b.txt");
System.out.println("b.txt的绝对路径是: " + realPath2);
// 下面代表获取src下的c.txt文件的真实路径
String realPath3 = application.getRealPath("/WEB-INF/classes/c.txt");
System.out.println("c.txt文件的绝对路径是: " + realPath3);
/*
* src目录下也叫classPath下, 也叫类路径下.
* web项目发布后, src下的所有.java文件将被编译后放到web/WEB-INF/classes目录下,
* web目录(Eclipse中叫WebContent目录)将更名成当前项目名并发布到tomcat的webapps
* 目录下.
*/
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
- 获取了文件的绝对路径, 就能通过IO流读写该文件了.
4. 通过类加载器来管理资源和配置文件
- 也就是通过类加载器来读写项目中的文件. 实际上也使用了IO流.
- java中的类加载器连.class文件都能加载, 那么加载其他类型的文本文件简直就是小菜一碟;
- 类加载器加载文件的方法:
InputStream inputStream =
this.getClass().getClassLoader().getResourceAsStream("欲加载的文件的路径");
只能加载类路径下(classpath下)的文件, 文件路径前不能加"/".InputStream inputStream = this.getClass().getResourceAsStream("欲加载的文件的路径");
只能加载类路径下(classpath下)的文件, 文件路径前能加"/", 加"/“和不加”/"的意义不同.
- 注意
如果使用 new FileInputStream(" 欲加载的文件的路径");的方式,既能获取 InputStream 又能获取 OutputStream , 因此可以对配置文件进行读写; 能读写任意位置的文件;
如果使用 getResourceAsStream(" 欲加载的文件的路径");的方式,那么只能获取 InputStream, 因此只能对配置文件进行读操作; 只能读取类路径下(classpath下)的文件;
package cn.king.demo01;
import java.io.InputStream;
public class Demo01 {
public void fun1() {
// 注意下面两行代码
InputStream inputStream01 = this.getClass().getClassLoader().getResourceAsStream("");
InputStream inputStream02 = this.getClass().getResourceAsStream("");
/*
* 你每天都要喝可乐, 每次喝可乐都找我, 我要去商店买来给你喝,
* 久而久之, 觉得不方便,
* 干脆我自己也卖可乐, 你要喝我直接拿给你, 不需要再往商店跑了.
* 上述的话可以形容上面的两句代码.
*/
}
public void fun2() {
// 从classpath路径下寻找config.properties并加载
InputStream in01 =
Demo01.class.getResourceAsStream("/config.properties");
// 从Demo01类所在包中寻找config.properties并加载
InputStream in02 =
Demo01.class.getResourceAsStream("config.properties");
// 从Demo01类所在包下的resource目录中寻找config.properties并加载
InputStream in03 =
Demo01.class.getResourceAsStream("resource/config.properties");
/*
* 可见,用Demo01.class.getResourceAsStream("欲加载的文件的路径");时,
* 只能从类路径下加载资源.
* 文件路径前既可以加"/"也可以不加"/", 加和不加的意义不同.
*/
}
public void fun3() {
// 代表从类路径下寻找 config.properties 并加载.
InputStream in01 =
Demo01.class.getClassLoader().getResourceAsStream("config.properties");
// 代表从类路径下的 resource 目录下寻找 config.properties 并加载
InputStream in02 =
Demo01.class.getClassLoader().getResourceAsStream("resource/config.properties");
/*
* Demo01.class.getClassLoader().getResourceAsStream("欲加载的文件的路径");
* 只能从类路径下加载资源.
* 文件路径前不能加"/".
*/
}
}
package cn.king.demo01;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* 将db.properties封装进properties中
*/
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
InputStream resourceAsStream =
PropertiesDemo.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(resourceAsStream);
Set<Map.Entry<Object, Object>> entrySet = properties.entrySet();
for (Map.Entry entry : entrySet) {
System.out.println(entry.getKey() + "\t" + entry.getValue());
}
}
}
# db.properties
driverDriver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db_name?characterEncoding=UTF-8
username=root
password=root
5. 注意
- 只要是读写文件就必须使用IO.