1. 程式人生 > 實用技巧 >yaml檔案轉為properties——使用java實現

yaml檔案轉為properties——使用java實現

最近要用Java實現一個 將yaml檔案轉為properties形式的功能,作為一個老搬運工,肯定先查一查有沒有已經開源的程式碼啦,[狗頭]!

發現其實有許多線上轉換工具,比如:https://www.toyaml.com/,這是一個線上yaml與properties互轉的工具,效果很不錯,如果只是偶爾進行檔案互轉,可以考慮用這個,優點是簡單便捷。

然而,我需要一段Java程式碼來實現 yaml轉 properties的功能。。。

發現真有優秀的大佬分享了 yaml轉properties 的java程式碼,感謝大佬的分享,詳見:https://www.cnblogs.com/xujingyang/p/10613206.html

。簡單地測試了這份程式碼,優點是可以實現基本的轉換功能,但是我的需求比較多,還不能滿足要求。所以,基於這份程式碼,我進行了功能完善,支援更多的轉換邏輯。

好了,廢話不多說,下面開搞吧!


注意,由於借鑑了大佬的原始碼,所以下面的程式碼大體結構都是相似的。

步驟如下:

1、引入yaml轉properties所需的maven依賴

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-yaml</artifactId>
    <version>2.9.4</version>
</dependency>

2、工具類如下:

package com.zzy.utils;

import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLParser;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.LinkedList; import java.util.List; /** * @author zhongyuanzhao000 * @date 2020/08/27 */ public class FileTranferUtils { /** * tranfer yaml file to properties * @param path the path of yaml file */ public static void yaml2Prop(String path) { List<String> lines = new LinkedList<>(); // DOT表示用於隔開key中不同的鍵 final String DOT = "*"; //layerOfArray表示當前陣列是第幾層陣列,預設為0即沒有陣列;每遍歷到"["就增加1 int layerOfArray = 0; // inArrays的索引表示yml檔案中遍歷到的token位於第幾層陣列,而元素內容表示當前遍歷到的token仍在陣列內部,元素預設值為false boolean[] inArrays = new boolean[4]; // arrayIndexs的索引表示yml檔案中遍歷到的token位於第幾層陣列,而元素內容表示其對應的索引,元素預設值為0 int[] arrayIndexs = new int[4]; // arrayCuteds的索引表示yml檔案中遍歷到的token位於第幾層陣列,而元素內容表示 含有中括號的鍵是否已被切去,元素預設值為false boolean[] arrayCuteds = new boolean[4]; // 注意:上面3個數組,目前均初始化了4個元素值,對應0、1、2、3,表示可以解析最多3層陣列巢狀; // 若要更多層,修改該初始值即可 try { YAMLFactory yamlFactory = new YAMLFactory(); YAMLParser parser = yamlFactory.createParser(new InputStreamReader(new FileInputStream(path), Charset.forName("utf-8"))); String key = ""; //這裡的key是最終轉換出的properties檔案中key,並不是yml檔案中的鍵值對中的鍵 String value = null; // 先獲取到基於json格式的第一個token,便於後面的遍歷 JsonToken token = parser.nextToken(); while (token != null) { // 基於json格式,如果是一個物件開始(即遇到了左花括號"{"時) if (JsonToken.START_OBJECT.equals(token)) { // do nothing } else if (JsonToken.FIELD_NAME.equals(token)) { // 基於json格式,如果遇到鍵值對的鍵時 // 使用點"."分割每層的key if (key.length() > 0) { // 如果該物件在陣列中,並且key包含中括號的數量不等於 當前所在陣列的層次時,則新增上陣列索引 if (inArrays[layerOfArray] == true && containNumbers(key, "[") != layerOfArray) { key = key + "[" + arrayIndexs[layerOfArray] + "]"; } key = key + DOT; } key = key + parser.getCurrentName(); // 繼續遍歷下一個token token = parser.nextToken(); /******************************************************************************************/ //如果遇到左中括號"[",表示陣列的開始 if (JsonToken.START_ARRAY.equals(token)) { // 進入第一層陣列 layerOfArray++; inArrays[layerOfArray] = true; token = parser.nextToken(); } /******************************************************************************************/ // 如果遇到子物件的開始(即"{"),則跳入下一個迴圈 if (JsonToken.START_OBJECT.equals(token)) { continue; } /******************************************************************************************/ // 此時,當前token遍歷到了一個鍵值對的值時(即到了一個分支盡頭),需要將其放入string陣列中 value = parser.getText(); //如果這個值是單獨被包含在中括號陣列內(中括號內沒有鍵值對 對應的鍵),則key肯定還沒有在相應的鍵上新增索引,所以這裡要補上索引 if (inArrays[layerOfArray] == true && containNumbers(key, "[") != layerOfArray) { key = key + "[" + arrayIndexs[layerOfArray] + "]"; } lines.add(key + "=" + value); /******************************************************************************************/ // 每當遍歷完一個分支,需要將 key截斷到倒數第二個鍵 int dotOffset = key.lastIndexOf(DOT); if (key.length() - 1 == key.lastIndexOf("]")) { arrayCuteds[layerOfArray] = true; } if (dotOffset > 0) { key = key.substring(0, dotOffset); } else { // 若原key中沒有".",則key直接置為"" key = ""; } // 若截斷後剩下的key的最後一個鍵含有中括號,也就是該鍵的索引即將更新,則去除掉該中括號子串以便於後面新增新的索引 if (key.length() > 0 && key.length() - 1 == key.lastIndexOf("]")) { key = key.substring(0, key.lastIndexOf("[")); } }else if (JsonToken.END_OBJECT.equals(token)) { // 基於json格式,如果是一個物件結束(即遇到了右花括號"}"時) // 如果當前token在陣列內部,則不需要截斷 if (inArrays[layerOfArray]) { arrayIndexs[layerOfArray]++; } else { int dotOffset = key.lastIndexOf(DOT); if (dotOffset > 0) { // 若原key中還有".",則截斷到倒數第二個鍵 key = key.substring(0, dotOffset); } else { // 若原key中沒有".",則key直接置為"" key = ""; } } } else if (JsonToken.END_ARRAY.equals(token)) { //如果遇到右中括號"]",表示陣列的結束 // 若當前層次中 含有中括號的鍵未被切去 if (!arrayCuteds[layerOfArray]) { int dotOffset = key.lastIndexOf(DOT); if (dotOffset > 0) { // 若原key中還有".",則截斷到倒數第二個鍵 key = key.substring(0, dotOffset); } else { // 若原key中沒有".",則key直接置為"" key = ""; } } // 重置該層的變數 inArrays[layerOfArray] = false; arrayIndexs[layerOfArray] = 0; arrayCuteds[layerOfArray] = false; // 回退到上一層 layerOfArray--; // 若截斷後剩下的key的最後一個鍵含有中括號,也就是上一層中 該鍵的索引即將更新,則去除掉該中括號子串 以便於後面新增新的索引 if (key.length() > 0 && key.length() - 1 == key.lastIndexOf("]")) { key = key.substring(0, key.lastIndexOf("[")); } } token = parser.nextToken(); } parser.close(); // 將String字串陣列中的內容打印出來 for (String line : lines) { line = line.replace(DOT, "."); System.out.println(line); } } catch (Exception e) { throw new RuntimeException(e); } } /** * 計算 字串str中包含多少個 模式串s * @param str 主字串 * @param s 模式串 * @return */ private static int containNumbers(String str, String s) { int count = 0; for(int i = 0; i < str.length(); ){ int c = -1; c = str.indexOf(s); if (c != -1){ str = str.substring(c + 1); count ++; } else { break; } } return count; } }

使用yaml2Prop方法,指定yml檔案就可以輸出properties內容在控制檯上了。

如果需要了解該方法的程式碼,建議先參考jackson倉庫,然後將yml檔案內容轉為json形式,然後根據json形式來理解方法程式碼。

最後,如果要檢驗該方法的效果,可以使用線上yaml轉properties工具,然後將工具轉換結果 與 該方法結果比較即可。