【Java基础知识】Properties类的操作

Properties类的操作

1.Properties类概述

A : 属于集合类,是一个可以和IO流相结合使用的集合类。
B : 可保存在流中或从流中加载,属性列表中每个键及其对应值都是一个字符串。
C : 是Hashtable的子类,是一个Map集合,具有Map的属性。
class Properties extends Hashtable

public class PropertiesDemo {
    public static void main(String[] args) {
        Properties prop = new Properties();
        //添加元素
        prop.put("01", "hello");
        prop.put("02", "world");
        prop.put("03", "java");
        //遍历集合
        Set<Object> set = prop.keySet();
        for (Object key : set) {
            Object value = prop.get(key);
            System.out.println(key + "---" + value);
        }
    }
}

2.Properties类的特殊方法

A: public Object setProperty(String key,String value):添加元素
B: public String getProperty(String key): 获取元素
C: public Set stringPropertyNames(): 获取所有的键的集合

class Properties extends Hashtable { 
    //A:添加元素,调用的是底层Map的set()方法
    public synchronized Object setProperty(String key, String value) {
        return put(key, value);
    }
    //B:获取元素,底层是调用Map的get()方法
    public String getProperty(String key) {
        Object oval = super.get(key);
        String sval = (oval instanceof String) ? (String)oval : null;
        return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
    }
    //C:获取所有的键的集合,底层也是调用Map的keySet()方法。
    public Set<String> stringPropertyNames() {
        Hashtable<String, String> h = new Hashtable<>();
        enumerateStringProperties(h);
        return h.keySet();
    }
    private synchronized void enumerateStringProperties(Hashtable<String, String> h) {
        if (defaults != null) {
            defaults.enumerateStringProperties(h);
        }
        for (Enumeration e = keys() ; e.hasMoreElements() ;) {
            Object k = e.nextElement();
            Object v = get(k);
            if (k instanceof String && v instanceof String) {
                h.put((String) k, (String) v);
            }
        }
    }
}

演示案例:

public class PropertiesDemo2 {
    public static void main(String[] args) {
        Properties prop = new Properties();
        prop.setProperty("语文", "Chinese");
        prop.setProperty("数学", "Math");
        prop.setProperty("英语", "English");

        Set<String> set = prop.stringPropertyNames();
        for (String key : set) {
            String value = prop.getProperty(key);
            System.out.println(key + "---" + value);
        }
    }
}

3.读属性、写属性以及需要注意的问题。

这里的集合必须是Properties集合:
public void load(Reader reader):把文件中的数据读取到集合中。
public void store(Writer writer, String comments):把集合中的数据存储到文件。

public class PropertiesDemo3 {
    public static void main(String[] args) throws IOException {
        myLoad();
        myStore();
    }

    private static void myStore() throws IOException {
        Properties prop = new Properties();

        prop.setProperty("语文", "Chinese");
        prop.setProperty("数学", "Math");
        prop.setProperty("英语", "English");      
        //public void store(Writer writer,String comments):把集合中的数据存储到文件
        Writer w = new FileWriter("course.txt");
        prop.store(w, "科目中英文对照");
        w.close();
    }
    private static void myLoad() throws IOException {
        Properties prop = new Properties();

        /*public void load(Reader reader):把文件中的数据读取到集合中。
             注意:这个文件的数据必须是键值对形式
         */
        Reader r = new FileReader("course.txt");    
        prop.load(r);
        r.close();
        System.out.println("prop:" +prop);
    }
}   

在JDK文档中我们看到同名方法如下:
load(InputStream inStream)
store(OutputStream out, String comments)
若是中文文本会出现乱码,为什么?
原因:在Properties类中store(OutputStream out, String comments)方法,已经把输入流的格式写死了【格式为ISO-8859-1】。
load(InputStream inStream) 将InputStream装换成内部类LineReader,字节流使用ISO8859-1来解码。
见源码:

    public void store(OutputStream out, String comments) throws IOException {
        store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")), comments, true);           
    }
    load(OutputStream out, String comments),源码还是将OutputStream转换成LineReader,【其中LineReader是Properties的内部类】
    public synchronized void load(InputStream inStream) throws IOException {
        load0(new LineReader(inStream));
    }
    /*
    Properties从流中加载属性集合,是通过将流中或者字节分成一行行来处理的。
    LineReader的定义如下:
     */ 
    class LineReader {
        public LineReader(InputStream inStream) {
            this.inStream = inStream;
            inByteBuf = new byte[8192];
        }

        public LineReader(Reader reader) {
            this.reader = reader;
            inCharBuf = new char[8192];
        }

        byte[] inByteBuf;
        char[] inCharBuf;
        char[] lineBuf = new char[1024];
        int inLimit = 0;
        int inOff = 0;
        InputStream inStream;
        Reader reader;

        //读取一行
        int readLine() throws IOException {
            int len = 0;
            char c = 0;

            boolean skipWhiteSpace = true;      //空白
            boolean isCommentLine = false;      //注释
            boolean isNewLine = true;           //新行
            boolean appendedLineBegin = false;  //加至行开始
            boolean precedingBackslash = false; //反斜杠 "\"
            boolean skipLF = false;

            while (true) {
                if (inOff >= inLimit) {
            /*从输入流中读取一定数量的字节并将其存在缓冲区数组inCharBuf/inByteBuf中,
              这里区分字节流和字符流
            */
                    inLimit = (inStream==null)?reader.read(inCharBuf)
                                              :inStream.read(inByteBuf);
                    inOff = 0;
                    //读取到的为空
                    if (inLimit <= 0) {
                        if (len == 0 || isCommentLine) {
                            return -1;
                        }
                        return len;
                    }
                }
                if (inStream != null) {
                    //字节流,使用ISO8859-1来解码
                    //The line below is equivalent to calling a
                    //ISO8859-1 decoder.
                    c = (char) (0xff & inByteBuf[inOff++]);
                } else {
                    c = inCharBuf[inOff++];
                }
                if (skipLF) {
                    skipLF = false;
                    if (c == '\n') {
                        continue;
                    }
                }
                if (skipWhiteSpace) {
                    if (c == ' ' || c == '\t' || c == '\f') {
                        continue;
                    }
                    if (!appendedLineBegin && (c == '\r' || c == '\n')) {
                        continue;
                    }
                    skipWhiteSpace = false;
                    appendedLineBegin = false;
                }
                if (isNewLine) {
                    isNewLine = false;
                    if (c == '#' || c == '!') {
                        //注释行,忽略。
                        isCommentLine = true;
                        continue;
                    }
                }
                //读取真正的属性内容
                if (c != '\n' && c != '\r') {
                    //这里类似于ArrayList内部的容量扩充,使用字符数组来保存读取的内容。
                    lineBuf[len++] = c;
                    if (len == lineBuf.length) {
                        int newLength = lineBuf.length * 2;
                        if (newLength < 0) {
                            newLength = Integer.MAX_VALUE;
                        }
                        char[] buf = new char[newLength];
                        System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length);
                        lineBuf = buf;
                    }
                    //flip the preceding backslash flag
                    if (c == '\\') {
                        precedingBackslash = !precedingBackslash;
                    } else {
                        precedingBackslash = false;
                    }
                }
                else {
                    // reached EOL文件结束
                    if (isCommentLine || len == 0) {
                        isCommentLine = false;
                        isNewLine = true;
                        skipWhiteSpace = true;
                        len = 0;
                        continue;
                    }
                    if (inOff >= inLimit) {
                        inLimit = (inStream==null)
                                  ?reader.read(inCharBuf)
                                  :inStream.read(inByteBuf);
                        inOff = 0;
                        if (inLimit <= 0) {
                            return len;
                        }
                    }
                    //反斜杠
                    if (precedingBackslash) {
                        len -= 1;
                        //skip the leading whitespace characters in following line
                        skipWhiteSpace = true;
                        appendedLineBegin = true;
                        precedingBackslash = false;
                        if (c == '\r') {
                            skipLF = true;
                        }
                    } else {
                        return len;
                    }
                }
            }
        }
    }

4.stringPropertyNames()方法的使用案例。

/*
 *文本文件(user.txt),我知道数据是键值对形式的,但是不知道具体内容。
 *写一程序判断是否有"Chinese"这样的键存在,如果有就改变其实为"90"。 
 * 分析:
 *      A:把文件中的数据加载到集合中
 *      B:遍历集合,获取得到每一个键
 *      C:判断键是否有为"Chinese"的,如果有就修改其值为"90"
 *      D:把集合中的数据重新存储到文件中
 */
public class PropertiesTest {
    public static void main(String[] args) throws IOException {
        Properties prop = new Properties();
        Reader r = new FileReader("user.txt");
        prop.load(r);
        r.close();
        Set<String> set = prop.stringPropertyNames();
        for (String key : set) {
            if ("Chinese".equals(key)) {
                prop.setProperty(key, "90");
                break;
            }
        }
        Writer w = new FileWriter("user.txt");
        prop.store(w, null);
        w.close();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值