对于很多java开发者,第一次接触这个Properties
类的时候可能是在接触Spring框架时,以为这是框架提供的功能,其实他是地地道道的JDK原生工具类。代表一个持久的属性集合,属性可以被保存到一个流或者从流中加载。属性列表中每一个键和对应的值都是字符串。
Properties类以一个简单的面向行的格式
从输入流中读取一个属性列表(key,value对)。遇到换行符才才认为行结束,它读取的逻辑行,逻辑行可以通过使用反斜杠字符\
转义行终止序列,从而使逻辑行跨越多个自然行,简单说可以通过\来把多个自然行续成一个逻辑行。
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) {
//1. 读取整个文件内容总长度
inLimit = (inStream==null)?reader.read(inCharBuf)
:inStream.read(inByteBuf);
inOff = 0;
if (inLimit <= 0) {//没有内容直接返回
if (len == 0 || isCommentLine) {
return -1;
}
if (precedingBackslash) {
len--;
}
return len;
}
}
if (inStream != null) {//有内容
//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') {
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) {
if (precedingBackslash) {
len--;
}
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;
}
}
}
}
加载输入流,并转换成Properties,每读取一行,找到首次出现的= :空格,之前的作为key值,之后的作为value
private void load0 (LineReader lr) throws IOException {
char[] convtBuf = new char[1024];
int limit;
int keyLen;
int valueStart;
char c;
boolean hasSep;
boolean precedingBackslash;
/**lr.readLine()每次读取一个逻辑行,遇到换行会结束
返回,这个逻辑行有效长度,直到读取不到数据结束
*/
while ((limit = lr.readLine()) >= 0) {
c = 0;
keyLen = 0;
valueStart = limit;
hasSep = false;
//System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
precedingBackslash = false;
while (keyLen < limit) {//对逻辑行一个字节一个字节的处理
c = lr.lineBuf[keyLen];
//need check if escaped.
//首次遇到等号、:、或者空格找到了key,value从下一个字符开始
if ((c == '=' || c == ':') && !precedingBackslash) {
valueStart = keyLen + 1;
hasSep = true;
break;
} else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) {
valueStart = keyLen + 1;
break;
}
if (c == '\\') {
precedingBackslash = !precedingBackslash;
} else {
precedingBackslash = false;
}
keyLen++;
}
while (valueStart < limit) {
c = lr.lineBuf[valueStart];
if (c != ' ' && c != '\t' && c != '\f') {
if (!hasSep && (c == '=' || c == ':')) {
hasSep = true;
} else {
break;
}
}
valueStart++;
}
String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
put(key, value);
}
}
Properties pt = new Properties();
pt.load(new FileInputStream("src/main/resources/myp.txt"));
Set keyset = pt.keySet();
for(Object key:keyset){
System.out.println(key + "=" + pt.getProperty(key.toString()));
}