snakeyaml操作yml文件中注释的处理

大家好,我是知秋君,一个会写博客吟诗的知秋码农。今天说一说snakeyaml操作yml文件中注释的处理,希望能够帮助大家进步!!! 情景 snakeyaml支持yml配置文件转map 也支持map转成yml文件 但是有些业务情景下会存在: yml配置文件转成map后,对<key,value>形式的map的数据进行处理, 比如增加、删除配置,或者修改配置的值,

大家好,我是知秋君,一个会写博客吟诗的知秋码农。今天说一说snakeyaml操作yml文件中注释的处理,希望能够帮助大家进步!!!

情景

snakeyaml支持yml配置文件转map 也支持map转成yml文件 但是有些业务情景下会存在: yml配置文件转成map后,对<key,value>形式的map的数据进行处理, 比如增加、删除配置,或者修改配置的值, 然后再生成新的yml配置文件,这时导致的问题就是以前的yml文件的注释在新的yml配置文件中都没有了 
只听到从知秋君办公室传来知秋君的声音:

岁暮锄犁傍空室,呼儿登山收橡实。有谁来对上联或下联?

解决办法

  1. 一开始考虑查看snakeyaml的源码,尝试覆盖一些源码的类去解决,能力有限,没尝试成功。
  2. 只能想到对文件进行处理了,对一开始的yml文件中的注释进行缓存,再生成新的yml文件后再把缓存好的注释正确的放进去
  3. 问题:如何缓存,如何正确的放入新的yml中?
  4. 个人方法:
此代码由一叶知秋网-知秋君整理
首先:检查需要引入snakeyaml的依赖 代码:分为三个类 YamlUtils -- 对yml文件操作的工具类 CommentUtils -- 继承YamlUtils,对注解的处理(缓存注解,放入新的yml文件中) Comment -- 注释对象

YamlUtils

public class YamlUtils { private static final Logger logger = LoggerFactory.getLogger(YamlUtils.class); public static Map<String, Object> yml2Map(String path) throws FileNotFoundException { FileInputStream fileInputStream = new FileInputStream(path); Yaml yaml = new Yaml(); Map<String, Object> ret = (Map<String, Object>) yaml.load(fileInputStream); return ret; } public static void map2Yml(Map<String, Object> map, String path) throws IOException { File file = new File(path); FileWriter fileWriter = new FileWriter(file); DumperOptions options = new DumperOptions(); options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); Yaml yaml = new Yaml(options); yaml.dump(map, fileWriter); } } 

Comment

此代码由一叶知秋网-知秋君整理
public class Comment { /** * 替换前的 */ private String key; /** * 替换后的 */ private String replaceKey; /** * 位置(默认为1,一般替换前的行内容(key)都不一样):若存在替换前的行内容(key)一致,则需此参数 */ private Integer sort; public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getReplaceKey() { return replaceKey; } public void setReplaceKey(String replaceKey) { this.replaceKey = replaceKey; } public Integer getSort() { return sort; } public void setSort(Integer sort) { this.sort = sort; } }

CommentUtils

class CommentUtils extends YamlUtils { private static volatile List<Comment> commentList; private final static String C = "#"; private final static Integer ONE = 1; private final static String ENTER = "\r\n"; private final static String CHARSET = "UTF-8"; /*public static void main(String[] args) { Map<String, Object> map = null; String path1 = "C:\\Users\\work\\Hzero\\hzero-generator\\src\\main\\resources\\application.yml"; String path2 = "C:\\Users\\work\\Hzero\\hzero-helper-parent\\hzero-helper-upgrade\\test.yml"; try { // 1 map = yml2Map(path1); buildComment(path1); // 2 map2Yml(map, path2); addComment(path2); } catch (IOException e) { e.printStackTrace(); } }*/ public static void buildComment(String path) { commentList = new ArrayList<>(); Map<String, Integer> keyCountMap = new HashMap<>(); try { List<String> lines = FileUtils.readLines(new File(path), CHARSET); for (int i = 0; i < lines.size(); i++) { String line = lines.get(i); String tempStr = line.trim(); if (tempStr.startsWith(C)) { String nextLine = lines.get(i+1); Comment comment = new Comment(); comment.setKey(nextLine); comment.setReplaceKey(line + ENTER + nextLine); comment.setSort(keyCountMap.merge(nextLine, ONE, Integer::sum)); commentList.add(comment); } else { if (tempStr.contains(C)) { String key = (C + StringUtils.substringBefore(line, C)).trim().substring(1); Comment comment = new Comment(); comment.setKey(key); comment.setReplaceKey(line); comment.setSort(keyCountMap.merge(key, ONE, Integer::sum)); commentList.add(comment); } } } } catch (IOException e) { e.printStackTrace(); } } public static void addComment(String path) { try { String content = FileUtils.readFileToString(new File(path), CHARSET); for (Comment comment : commentList) { content = replacePosition(content, comment.getKey(), comment.getReplaceKey(), comment.getSort()); } FileUtils.writeStringToFile(new File(path), content, CHARSET); } catch (IOException e) { e.printStackTrace(); } } /** * 替换第position个匹配的目标子串 * @param str 源字符串。 * @param target 需要替换的目标子串。 * @param replacement 需要替换成的字符串。 * @return 将源字符串中出现的第n个target换成replacement后的字符串。 */ public static String replacePosition(String str, String target, String replacement, int position) { if (str == null || target == null || replacement == null) { throw new NullPointerException(); } if (position < 2) { return str.replaceFirst(target, replacement); } String result = str; for (int i = 1; i < position; i++) { result = replaceSecond(result, target, replacement); } return result; } /** * 替换第二个匹配的目标子串 * @param str 源字符串。 * @param target 需要替换的目标子串。 * @param replacement 需要替换成的字符串。 * @return 将源字符串中出现的第二个target换成replacement后的字符串。 */ public static String replaceSecond(String str, String target, String replacement){ if (str == null || target == null || replacement == null) { throw new NullPointerException(); } int index = str.indexOf(target); if (index == -1) { throw new RuntimeException("Not Found."); } index = str.indexOf(target, index + target.length()); if (index == -1) { throw new RuntimeException("Not Found."); } String str1 = str.substring(0, index); String str2 = str.substring(index); str2 = str2.replaceFirst(target, replacement); return str1 + str2; } } 

代码及其注释都很简单明了,稍微解释下之前第三点提的问题

  1. buildComment方法去缓存一开始的yml文件中的注释
    key – 表示带有注释的那一行的实际内容
    replaceKey – 要替换key的内容
    sort – key的顺序
    比如:

    # 服务端口 server: port: ${HGEN_SERVER_PORT:8265} management: # actuator监控端口 server: port: ${HGEN_MANAGEMENT_SERVER_PORT:8266} endpoints: web: exposure: include: '*' #这是注释 

    举例:
    一:注释在头上(1)

    # 服务端口 server: 

    此时,
    key为

    server: 

    replaceKey为

    # 服务端口 server: 

    sort为默认值1,因为整个文件中key为

    server: 

    的只有这一行

    二:注释在头上(2)

     # actuator监控端口 server: 

    此时,
    key为

     server: 

    replaceKey为

     # actuator监控端口 server: 

    sort为默认值1,因为整个文件中key为

     server: 

    的只有这一行
    (注意看空格,因为存在空格所以上面两个key是不一样的,如果存在一样的key时,后面的key的sort会按顺序累加)

    三:注释在后面

     include: '*' #这是注释 

    此时,
    key为

     include: '*' 

    replaceKey为

     include: '*' #这是注释 

    sort为默认值1,因为整个文件中key为

     include: '*' 

    的只有这一行

  2. addComment方法中把生成好的yml文件读成String,再循环缓存好的注释Comment对象List,通过replacePosition方法把带注释的内容替换进去,再写成文件。replacePosition和replaceSecond方法在代码中都有详细的说明

知秋君
上一篇 2024-07-03 15:31
下一篇 2024-07-03 15:31

相关推荐