![](/img/trans.png)
[英]What is the best way of reading configuration parameters from configuration file in Java?
[英]What is the best way to parse this configuration file?
我正在開發一個使用自定義配置文件的個人項目。 該文件的基本格式如下所示:
[users]
name: bob
attributes:
hat: brown
shirt: black
another_section:
key: value
key2: value2
name: sally
sex: female
attributes:
pants: yellow
shirt: red
可以有任意數量的用戶,每個用戶可以有不同的鍵/值對,並且可以使用制表位在一個節下面嵌套鍵/值。 我知道我可以為這個配置文件使用json,yaml甚至xml,但是,我現在想保持自定義。
解析應該不難,因為我已經編寫了解析它的代碼。 我的問題是,使用干凈和結構化的代碼解析這個問題的最佳方法是什么,以及在未來不會發生變化的方式編寫(未來可能會有多個嵌套)。 現在,我的代碼看起來非常惡心。 例如,
private void parseDocument() {
String current;
while((current = reader.readLine()) != null) {
if(current.equals("") || current.startsWith("#")) {
continue; //comment
}
else if(current.startsWith("[users]")) {
parseUsers();
}
else if(current.startsWith("[backgrounds]")) {
parseBackgrounds();
}
}
}
private void parseUsers() {
String current;
while((current = reader.readLine()) != null) {
if(current.startsWith("attributes:")) {
while((current = reader.readLine()) != null) {
if(current.startsWith("\t")) {
//add user key/values to User object
}
else if(current.startsWith("another_section:")) {
while((current = reader.readLine()) != null) {
if(current.startsWith("\t")) {
//add user key/values to new User object
}
else if (current.equals("")) {
//newline means that a new user is up to parse next
}
}
}
}
}
else if(!current.isEmpty()) {
//
}
}
}
正如你所看到的,代碼非常混亂,我在這里簡化了演示。 我覺得有更好的方法可以做到這一點,也許不使用BufferedReader。 有人可以提供一種更好的方式或方法,而不是像我的那樣復雜嗎?
每個人都會建議使用XML,因為它更好。
但是,如果您正在尋求證明您的程序員對自己的價值......
......你發布的代碼沒有任何根本性的錯誤,因為它很清楚,對於潛在的讀者而言顯而易見的是,除非我完全脫離文件操作的循環,它應該表現得非常好盡可能的。
我能提出的一個批評是它不是遞歸的。 每個級別都需要支持新級別的代碼。 我可能會做一個遞歸函數(一個用子內容作為參數調用自身的函數,然后再調用子子內容等),可以調用,將所有這些東西讀入帶有哈希表的哈希表中,然后我將該哈希表用作配置對象。
然后,在那一點上,我可能會停止看到這一點並使用XML。 ;)
如果您可以使用XML或JSON或其他眾所周知的數據編碼作為數據格式,則解析/反序列化文本內容並提取值將更加容易。 例如。
name: bob
attributes:
hat: brown
shirt: black
another_section:
key: value
key2: value2
可以表示為以下XML(還有其他選項可以用XML表示)
<config>
<User hat="brown" shirt="black" >
<another_section>
<key>value</key>
<key2>value</key2>
</another_section>
</User>
</config>
自定義(非常簡單)正如我在下面的評論中提到的,您可以將它們全部設置為名稱和值對。 例如
name :bob
attributes_hat :brown
attributes_shirt :black
another_section_key :value
another_section_key2 :value2
然后在'\\ n'(換行符)和':'上進行字符串拆分以提取鍵和值或構建字典/地圖對象。
對於狀態機而言看起來很簡單。
while((current = reader.readLine()) != null) {
if(current.startsWith("[users]"))
state = PARSE_USER;
else if(current.startsWith("[backgrounds]"))
state = PARSE_BACKGROUND;
else if (current.equals("")) {
// Store the user or background that you've been building up if you have one.
switch(state) {
case PARSE_USER:
case USER_ATTRIBUTES:
case USER_OTHER_ATTRIBUTES:
state = PARSE_USER;
break;
case PARSE_BACKGROUND:
case BACKGROUND_ATTRIBUTES:
case BACKGROUND_OTHER_ATTRIBUTES:
state = PARSE_BACKGROUND;
break;
}
} else switch(state) {
case PARSE_USER:
case USER_ATTRIBUTES:
case USER_OTHER_ATTRIBUTES:
if(current.startsWith("attributes:"))
state = USER_ATTRIBUTES;
else if(current.startsWith("another_section:"))
state = USER_OTHER_ATTRIBUTES;
else {
// Split the line into key/value and store into user
// object being built up as appropriate based on state.
}
break;
case PARSE_BACKGROUND:
case BACKGROUND_ATTRIBUTES:
case BACKGROUND_OTHER_ATTRIBUTES:
if(current.startsWith("attributes:"))
state = BACKGROUND_ATTRIBUTES;
else if(current.startsWith("another_section:"))
state = BACKGROUND_OTHER_ATTRIBUTES;
else {
// Split the line into key/value and store into background
// object being built up as appropriate based on state.
}
break;
}
}
// If you have an unstored object, store it.
我建議將配置文件的格式更改為JSON,並使用現有的庫來解析諸如FlexJSON之類的JSON對象。
{
"users": [
{
"name": "bob",
"hat": "brown",
"shirt": "black",
"another_section": {
"key": "value",
"key2": "value2"
}
},
{
"name": "sally",
"sex": "female",
"another_section": {
"pants": "yellow",
"shirt": "red"
}
}
]
}
一個很好的清理方法是使用一個表,即用Map替換你的條件。 然后,您可以通過反射(簡單)調用解析方法,或者創建一些實現公共接口的類(更多工作但更強大)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.