【常见配置文件】YAML 文件(Java)

1,416 阅读7分钟

YAML文件

YAML文件的定义

YAML (YAML Ain't Markup Language) 是一种轻量级的数据序列化格式,它的语法简单、易读、易写。YAML 文件通常以 .yml 或 .yaml 扩展名进行命名。

文件特点

  1. YAML 是一种“人类友好”的数据格式,它的语法结构简单、易于阅读和编写,使得 YAML 文件在可读性和可维护性方面比其他数据格式(如 JSON 或 XML)更具优势。
  2. YAML 文件支持多种数据类型,包括字符串、数字、布尔值、日期、时间、列表、对象等。它还支持引用、锚点、别名等特性,可以帮助减少文件的冗余度。
  3. 在 YAML 文件中,以“#”开头的行表示注释。注释可以出现在键值对或列表的任意一行,用于解释这些数据的含义或提供其他相关信息。
  4. YAML 文件可以嵌套和组合,这意味着在一个 YAML 文件中可以定义复杂的数据结构。例如,可以在一个列表中嵌套多个对象,或者在一个对象中嵌套多个列表。
  5. YAML 文件的解析和序列化非常方便,因为它可以很容易地转换为常见的编程语言数据结构,例如 Python 中的字典和列表、Java 中的 Map 和 List 等等。

总之,YAML 是一种优秀的数据格式,它的简洁易读性、灵活性和可扩展性使得它在许多场景下都是一个很好的选择。

YAML 文件基础语法

YAML 文件基础语法非常简单,主要由键值对和列表构成。键值对由键名和键值组成,用冒号分隔;列表由多个值组成,用短横线“-”表示。以下是一个基本的 YAML 文件示例:

# 注释
key1: value1
key2: value2
list:
  - item1
  - item2

在 YAML 文件中,以“#”开头的行表示注释,注释可以出现在任何位置。

YAML 文件数据类型

YAML 文件支持多种数据类型,包括字符串、数字、布尔值、日期、时间、列表、对象等。以下是一些常用的数据类型及其示例:

字符串

字符串可以使用单引号或双引号包裹,也可以不使用引号。如果字符串中包含特殊字符(如冒号、短横线等),则需要使用引号将其括起来。

str1: 'Hello, World!'
str2: "Hello, YAML!"
str3: Hello, YAML!
str4: 'a:b:c'

数字

数字可以是整数或浮点数,可以使用十进制、八进制、十六进制等表示法。

int1: 123
int2: -456
float1: 3.14
octal: 0o123
hex: 0x1a

布尔值

布尔值可以是 true 或 false。

bool1: true
bool2: false

日期和时间

日期和时间可以使用 ISO 8601 格式表示。

date: 2022-01-01
time: 10:30:00
datetime: 2022-01-01T10:30:00Z

列表

列表由多个值组成,用短横线“-”表示。

list:
  - item1
  - item2
  - item3

对象

对象由多个键值对组成,用冒号“:”分隔。

person:
  name: John
  age: 30
  hobbies:
    - hiking
    - reading

YAML 文件示例

以下是一个更复杂的 YAML 文件示例,展示了 YAML 文件的嵌套和组合特性:

# 注释
person:
  name: John Smith
  age: 30
  address:
    street: 123 Main St.
    city: San Francisco
    state: CA
    zip: 12345
  hobbies:
    - hiking
    - reading
    - traveling
  friends:
    - name: Jane Doe
      age: 28
      address:
        street: 456 Oak St.
        city: New York
        state: NY
        zip: 67890
    - name: Bob Johnson
      age: 32
      address:
        street: 789 Pine St.
        city: Los Angeles
        state: CA
        zip: 45678

这个 YAML 文件定义了一个人的信息,包括姓名、年龄、地址、爱好和朋友列表。其中,地址和朋友列表都是嵌套的对象,朋友列表中每个朋友也是一个嵌套的对象。

其它特性

YAML 还支持引用、锚点和别名等特性,这些特性可以帮助减少文件的冗余度。

引用

在 YAML 文件中,可以使用“&”字符定义一个引用,在其他位置使用“*”字符引用这个引用。引用可以是一个键、一个值或者一个对象。

# 定义引用
person: &person
  name: John Smith
  age: 30

# 使用引用
person1: *person
person2: *person

在这个示例中,我们定义了一个名为“person”的引用,它包含一个人的姓名和年龄。然后,我们使用“*person”在两个不同的位置引用了这个引用,这样就可以避免重复定义相同的数据。

锚点和别名

在 YAML 文件中,可以使用“&”字符定义一个锚点,在其他位置使用“*”字符引用这个锚点。锚点和引用的不同之处在于,锚点是一个对象或列表中的一部分,而引用是一个独立的键值对或值。

# 定义锚点
person:
  name: John Smith
  age: 30
  address: &address
    street: 123 Main St.
    city: San Francisco
    state: CA
    zip: 12345

# 使用别名
person1:
  <<: *person
  address: *address

在这个示例中,我们定义了一个名为“address”的锚点,它包含一个人的地址信息。然后,我们在一个新的对象中使用“<<: *person”将“person”对象的所有键值对复制到这个对象中,并在“address”键使用“*address”引用了锚点。这样一来,我们就可以避免重复定义相同的数据,同时还可以保持 YAML 文件的简洁性和可读性。

差不多了解语法之后,可以进行操作了


Java读取YAML文件

和property与XML不同,Java并没有自带的处理yml的库,因此需要引入第三方库GitHub - snakeyaml,ps: 我看见这个是springboot也在用的库,所以推荐给大家。

SnakeYAML 是一个 Java 库,用于解析和生成 YAML 格式的数据。它可以将 YAML 格式的数据转换为 Java 对象,也可以将 Java 对象转换为 YAML 格式的数据。以下是使用 SnakeYAML 的基本步骤:

  1. 添加 SnakeYAML 依赖

首先,需要将 SnakeYAML 依赖添加到项目中。可以通过 Maven 或 Gradle 等构建工具来添加依赖,例如:

<!-- Maven 依赖 -->
<dependency>
    <groupId>org.yaml</groupId>
    <artifactId>snakeyaml</artifactId>
    <version>1.29</version>
</dependency>
  1. 创建 Yaml 对象

接下来,需要创建 Yaml 对象。Yaml 对象是 SnakeYAML 库的核心类,用于解析和生成 YAML 格式的数据。可以使用默认构造函数创建 Yaml 对象,例如:

Yaml yaml = new Yaml();
  1. 解析 YAML 数据

要解析 YAML 数据,可以使用 Yaml 对象的 load() 方法。load() 方法接受一个输入流或字符串作为参数,可以将 YAML 数据解析为 Java 对象或 Map 对象。例如:

InputStream inputStream = new FileInputStream("example.yml");
// 将数据读进map
Map<String, Object> data = yaml.load(inputStream);

在这个示例中,我们创建了一个 FileInputStream 对象来读取名为 example.yml 的 YAML 文件,然后调用 Yaml 对象的 load() 方法将其解析为一个 Map 对象。

完整代码

package property;

import org.yaml.snakeyaml.Yaml;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Map;

public class Main {
    public static void main(String[] args) throws FileNotFoundException {
        Yaml yaml = new Yaml();
        InputStream inputStream = new FileInputStream("D:\works\untitled2\src\main\java\property\property.yml");
        Map<String, Object> data = yaml.load(inputStream);
        for (String s : data.keySet()) {
            System.out.println(data.get(s));
        }
    }
}

Java修改yml文件

在使用 SnakeYAML 将 YAML 数据解析为 Map 对象之后,可以使用类似于操作普通 Map 对象的方式来修改其中的数据。

import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import java.io.FileWriter;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        Yaml yaml = new Yaml();
        Map<String, Object> data = new LinkedHashMap<>();
        data.put("name", "Alice");
        data.put("age", 30);
        Map<String, String> address = new LinkedHashMap<>();
        address.put("street", "123 Main St");
        address.put("city", "Anytown");
        address.put("state", "CA");
        address.put("zip", "12345");
        data.put("address", address);
        try {
            FileWriter writer = new FileWriter("D:\works\untitled2\src\main\java\property\after.yml");
            // 默认是流式形式输出文件
            yaml.dump(data, writer);
            writer.close();
            System.out.println("YAML data written to file.");
        } catch (IOException e) {
            e.printStackTrace();
        }
        data.put("name", "Bob");
        data.put("age", 40);
        address.put("zip", "67890");
        try {
            FileWriter writer = new FileWriter("example.yml");
            DumperOptions options = new DumperOptions();
            // 将输出格式换为块级形式
            options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
            // 新建yml对象
            yaml = new Yaml(options);
            yaml.dump(data, writer);
            writer.close();
            System.out.println("YAML data updated in file.");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

知识点补充

DumperOptions 是 SnakeYAML 用于控制 YAML 数据输出格式的类,可以通过它来设置如何将数据转换为 YAML 格式。

在上述代码中,我们创建了一个 DumperOptions 对象,并使用 setDefaultFlowStyle() 方法来设置 YAML 数据的块式格式。在 YAML 中,块式格式使用缩进来表示层次关系,而流式格式使用花括号和逗号来表示。例如,下面是一个包含一个 Map 对象的 YAML 数据的块式格式和流式格式:

块式格式:

person:
  name: Alice
  age: 30
  address:
    street: 123 Main St
    city: Anytown
    state: CA
    zip: 12345

流式格式: (json)

person: {name: Alice, age: 30, address: {street: 123 Main St, city: Anytown, state: CA, zip: 12345}}

在实际应用中,可以根据需要选择合适的格式来输出 YAML 数据。如果数据包含较多的嵌套层次或较多的属性,那么块式格式可能更易于阅读和维护。如果数据比较简单或较少,那么流式格式可能更加紧凑和简洁。

知识点补充

只有在特殊情况下,YAML解析器才支持用=号连接列表元素,例如:

  • Spring Cloud Gateway 的 predicates 配置
  • Spring Boot 的 spring.sql.init.platform配置
routes:
  - id: service-hosp
    uri: lb://service-hosp
    predicates:
      - Path=/*/hosp/**
  - id: service-cmn
    uri: lb://service-cmn
      - Path=/*/cmn/**
  - id: service-user
    uri: lb://service-user
      - Path=/*/user/**