常用作配置文件的properties

  在实际开发过程中,对于系统中经常使用的一些基本不会改变的内容,如访问外部系统的url地址、数据库连接配置等等。通常有以下几种方式存储:

  1、存储在配置文件中:编码加载配置文件;配置中心Apollo

  2、存储在数据库中

  配置文件一般使用properties文件,下面就简单的使用jdk自带Properties的api,在src/properties目录下新建配置文件db.properties。

一、db.properties的配置文件

1 driverClass = com.mysql.cj.jdbc.Driver
2 jdbcUrl = jdbc:mysql://localhost:3306/test
3 user = root
4 password = root

二、读取配置文件信息

复制代码
 1 import java.io.BufferedInputStream;
 2 import java.io.FileInputStream;
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 import java.util.Properties;
 6 
 7 public class PropertiesDemo {
 8     public static void main(String[] args) {
 9         InputStream in = null;
10         try {
11             // ClassLoader加载配置文件
12             in = PropertiesDemo.class.getClass().getResourceAsStream("/properties/db.properties");
13             // 通过文件流读取
14 //            in = new BufferedInputStream(new FileInputStream("src/properties/db.properties"));    
15             Properties prop = new Properties();
16             try {
17                 prop.load(in);
18             } catch (IOException e) {
19                 e.printStackTrace();
20             }
21             String driverClass = prop.getProperty("driverClass");
22             String jdbcUrl = prop.getProperty("jdbcUrl");
23             String user = prop.getProperty("user");
24             String password = prop.getProperty("password");
25             System.out.println("数据库驱动: " + driverClass + "; \n数据库url: " + jdbcUrl + "; \n数据库用户: " + user + "; \n数据库密码: " + password);
26         }catch (Exception e1) {
27             e1.printStackTrace();
28         }finally {
29             // 关闭流
30             if(in != null) {
31                 try {
32                     in.close();
33                 } catch (IOException e) {
34                     e.printStackTrace();
35                 }
36             }
37         }
38     }
39 }
复制代码

三、运行结果

 四、Properties源码分析

1、Properties类的继承自Hashtable。

  方法setProperty(String, String)、getProperties(String)就是利用Hashtable的put/get方法实现的。

public class Properties extends Hashtable<Object,Object>{}

2、Properties的构造方法

复制代码
/**
     * 创建一个没有指定默认属性的Properties
     */
    public Properties() {
        this(null);
    }

    /**
     * 创建一个有指定默认属性的Properties
     */
    public Properties(Properties defaults) {
        this.defaults = defaults;
    }
复制代码

3、Properties的load(InputStream in)方法

  Properties所有加载流的方法都是都调用了load0(LineReader lr)方法。

3.1、内部类LineReader

     LineReader是Properties的一个内部类,作用是过滤properties文件中的注释、空格等内容,并将过滤后的内容存储在内存中,

即lineBuf[]字符数组中。下面看一下LineReader的方法,支持输入流、字符流的构造函数。

   

 

3.2、load0(LineReader lr)方法

复制代码
private void load0 (LineReader lr) throws IOException {
        // 转换的字符数组
        char[] convtBuf = new char[1024];
        // 读取当前行的长度
        int limit;
        // key的长度
        int keyLen;
        // value的开始位置
        int valueStart;
        // 比较的当前字符
        char c;
        // 连接符处理标识
        boolean hasSep;
        // 转义字符标识
        boolean precedingBackslash;
        // 当前行的内容不为空
        while ((limit = lr.readLine()) >= 0) {
            c = 0;
            keyLen = 0;
            valueStart = limit;
            hasSep = false;

            //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
            precedingBackslash = false;
            // 读取key的内容
            while (keyLen < limit) {
                // 获取key中的字符
                c = lr.lineBuf[keyLen];
                //need check if escaped.
                // 此处解释了properties文件中key、value的书写方式:key=value、key:value,并且判断前一个字符不是转义字符
                if ((c == '=' ||  c == ':') && !precedingBackslash) {
                    valueStart = keyLen + 1;
                    // 设置连接符处理标识
                    hasSep = true;
                    break;
                // tab方式、空格方式的key、value也可被读取
                } else if ((c == ' ' || c == '\t' ||  c == '\f') && !precedingBackslash) {
                    valueStart = keyLen + 1;
                    break;
                }
                 // 当前读取的字符为'\\',更新是否是转义字符标识
                if (c == '\\') {
                    precedingBackslash = !precedingBackslash;
                } else {
                    precedingBackslash = false;
                }
                keyLen++;
            }
            // 读取value的内容
            while (valueStart < limit) {
                c = lr.lineBuf[valueStart];
                if (c != ' ' && c != '\t' &&  c != '\f') {
                    if (!hasSep && (c == '=' ||  c == ':')) {
                        hasSep = true;
                    } else {
                        break;
                    }
                }
                valueStart++;
            }
            // 将字符数组中的key、value转化为字符串
            String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
            String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
            // Hashtable的put方法,将key、value存储在内存中
            put(key, value);
        }
    }
复制代码

        load0()方法作用是读取在LineReader中得到的字符数组,由特定的连接符(如’=’、’:’)为标记位获得key、value的长度,通过key、value的长度获取字符数组中的对应的内容并转为字符串,将键值对通过Hashtable的put方法存储在内存中。

4、Properties的getProperties(String)方法

  

  通过HashTable的get方法获取指定key的内容,若得到的结果不是String类型的,并且在初始化Properties时没有自定义的Properties内容,则返回null。否则读取自定义Properties中的内容并返回。

5、Properties的setProperties(String, String)方法

   

   调用Hashtable的put方法,将指定key、value设置进内存中。此时的新加的key、value并未保存在properties文件中,若需要将内荣保存在properties中还需要调用store方法。

6、Properties的store(Writer, String)方法

     

    store(...)方法调用store0()方法,代码如下

复制代码
private void store0(BufferedWriter bw, String comments, boolean escUnicode)
        throws IOException
{
       // 添加评论
        if (comments != null) {
            writeComments(bw, comments);
        }
        // 添加文件创建日期
        bw.write("#" + new Date().toString());
       // 换行
        bw.newLine();
        synchronized (this) {
            // 遍历键key
            for (Enumeration<?> e = keys(); e.hasMoreElements();) {
                 // 获取键key
                String key = (String)e.nextElement();
// 获取值value
                String val = (String)get(key);
  // 获取key的单个字符做处理后,用StringBuffer拼接返回处理后的key
                key = saveConvert(key, true, escUnicode);
  // 获取value的单个字符做处理后,用StringBuffer拼接返回处理后的value
                val = saveConvert(val, false, escUnicode);
  // 将key、value 用’=’连接写入
                bw.write(key + "=" + val);
 // 换行
                bw.newLine();
            }
        }
        // 刷新写入
        bw.flush();
    }
复制代码

  store0方法的作用将内存中Hashtable的数据通过指定编码持久化到指定的文件中,keyvalue统一用’=’做连接符。

  下面是一个用store方法的简单demo。

复制代码
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.util.Properties;

public class PropertiesDemo {
    public static void main(String[] args) {
        InputStream in = null;
        try {
            // ClassLoader加载配置文件
            in = PropertiesDemo.class.getClass().getResourceAsStream("/properties/db.properties");
            Properties prop = new Properties();
            try {
                prop.load(in);
            } catch (IOException e) {
                e.printStackTrace();
            }
            // setProperty将test键值对通过Hashtable保存在内存中
            prop.setProperty("test", "test");
            System.out.println(prop);
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File("src/properties/db1.properties"))));
            // 将内存中的键值对持久化到db1.properties文件中
            prop.store(bw, "add key-test, value-test");
            bw.close();
        }catch (Exception e1) {
            e1.printStackTrace();
        }finally {
            // 关闭流
            if(in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
复制代码

  db1.properties的内容如下,新加的内容test已经保存在文件中。

   

posted @   无虑的小猪  阅读(330)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示

目录在这里