文盤Rust -- 如何把配置檔案打包到二進位制檔案裡

京東雲發表於2022-09-13

在實際開發中,經常會遇到各種不同的配置檔案。通常,程式執行的各種配置從外部讀取,以增強應用配置的靈活性。java 生態中的 springboot 提供了這種設計的典範。springboot 的應用程式,預設透過 application.yml 載入配置。預設的 application.yml 檔案打進 jar 包,如果想改變程式的行為,可以在jar 包的同級目錄下建立 application.yml 檔案或者透過引數指定配置檔案位置。那麼在 rust 生態裡有沒有辦法把預設配置檔案打包到二進位制檔案呢。
我們可以透過 [rust-embed](
https://github.com/pyrossh/rust-embed) 第三方庫來實現這一效果。

在實際開發中的典型場景是: 不指定任何配置檔案時,使用預設配置檔案;當應用程式同級目錄下包含配置檔案時載入該配置檔案。

* 定義嵌入檔案的位置及獲取函式

src/resources/embed_resource.rs 中定義了嵌入檔案的位置及獲取函式

```rust  use rust_embed::RustEmbed;  #[derive(RustEmbed)]
  #[folder = "src/embedfiles/"]
  struct Asset;  pub fn get_app_default() -> Option<rust_embed::EmbeddedFile> {
    Asset::get("./app_default.yml")
  }
  ```

宏定義了嵌入檔案的目錄 '#[folder = "src/embedfiles/"]',獲取檔案函式以該目錄為根。

* 使用嵌入檔案

  ```rust  fn main() {    if Path::new("./app.yml").exists() {        let contents =
            fs::read_to_string("./app.yml").expect("Read file error!");        println!("{}", contents);        return;
    }    let app = get_app_default().unwrap();    let f = std::str::from_utf8(app.data.as_ref()).unwrap();    println!("{}", f);
  }
  ```

按照優先順序,我們先檢查應用同級目錄下有沒有app.yml檔案,如果有就載入,否則載入預設配置檔案。我們先前定義的獲取嵌入檔案的函式會返回rust_embed::EmbeddedFile 的 struct。透過解析該 struct 的 data 成員,獲取檔案內容。

* 測試
為了避免干擾,我們把編譯好的應用 mv 到 /tmp 目錄

  ```shell
  cargo build
  mv target/debug/embed /tmp
  ```

先執行 embed ,可以看到,輸出的是預設配置檔案的內容;在應用程式同級目錄建立 app.yml 檔案,隨便填寫些內容,再執行 embed 則輸出的是 app.yml 檔案的內容。

[原始碼地址](
https://github.com/jiashiwen/wenpanrust/tree/main/embed)

以上示例在 macos 上編譯執行透過,我們們下期見

作者:賈世聞


相關文章