Skip to main content
On this page

@std/ini

不稳定

此 @std 包是实验性的,其 API 可能在未增加主版本号的情况下发生变化。

概览 Jump to heading

parsestringify 用于处理 INI 编码数据,比如 桌面条目规范。 默认情况下,数值被解析为字符串,以保持与原始数据一致性。 也可以通过类似 JSON.parseJSON.stringify 中的 reviver/replacer 函数进行自定义。 不支持嵌套节、小节内重复键名和键/值数组,但使用 IniMap 时这些会被保留。 多行值不支持,遇到会抛出语法错误。 空白填充和以 '#', ';' 或 '//' 开头的行将被视为注释。

import * as ini from "@std/ini";
import { assertEquals } from "@std/assert";

const iniFile = `# 例子配置文件
Global Key=Some data here

[Section #1]
Section Value=42
Section Date=1977-05-25`;

const parsed = ini.parse(iniFile, {
  reviver(key, value, section) {
    if (section === "Section #1") {
      if (key === "Section Value") return Number(value);
      if (key === "Section Date") return new Date(value);
    }
    return value;
  },
});

assertEquals(parsed, {
  "Global Key": "Some data here",
  "Section #1": {
    "Section Value": 42,
    "Section Date": new Date("1977-05-25T00:00:00.000Z"),
  },
});

const text = ini.stringify(parsed, {
  replacer(key, value, section) {
    if (section === "Section #1" && key === "Section Date") {
      return (value as Date).toISOString().split("T")[0];
    }
    return value;
  },
});

assertEquals(text, `Global Key=Some data here
[Section #1]
Section Value=42
Section Date=1977-05-25`);

也可以使用 IniMap 来进行更精细的 INI 操作。使用此类可以保留注释, 像使用映射一样访问值,迭代键/值/节条目等更多功能。

import { IniMap } from "@std/ini/ini-map";
import { assertEquals } from "@std/assert";

const ini = new IniMap();
ini.set("section1", "keyA", 100);
assertEquals(
  ini.toString(),
  `[section1]
keyA=100`,
);

ini.set("keyA", 25);
assertEquals(ini.toObject(), {
  keyA: 25,
  section1: {
    keyA: 100,
  },
});

reviver 和 replacer API 可用于扩展 IniMap 的行为,例如为重复键提供像值数组一样的支持。

import { IniMap } from "@std/ini/ini-map";
import { assertEquals } from "@std/assert";

const iniFile = `# key/value 数组示例
[section1]
key1=This key
key1=is non-standard
key1=but can be captured!`;

const ini = new IniMap({ assignment: "=", deduplicate: true });
ini.parse(iniFile, (key, value, section) => {
  if (section) {
    if (ini.has(section, key)) {
      const exists = ini.get(section, key);
      if (Array.isArray(exists)) {
        exists.push(value);
        return exists;
      } else {
        return [exists, value];
      }
    }
  }
  return value;
});

assertEquals(
  ini.get("section1", "key1"),
  ["This key", "is non-standard", "but can be captured!"],
);

const result = ini.toString((key, value) => {
  if (Array.isArray(value)) {
    return value.join(
      `${ini.formatting.lineBreak}${key}${ini.formatting.assignment}`,
    );
  }
  return value;
});

assertEquals(result, iniFile);

添加到你的项目 Jump to heading

deno add jsr:@std/ini

查看 @std/ini 中所有符号

什么是 INI 文件? Jump to heading

INI 文件是用作配置的简单文本文件。它们由键值对组成,按节分组,便于人类阅读和编辑。INI 文件常用于应用设置、偏好和其他配置数据。

为什么使用 @std/ini? Jump to heading

  • INI 规范较宽松;推荐使用简单的键/值及扁平化的节以获得最佳互操作性。
  • 默认解析值为字符串。使用 reviver/replacer 明确转换为数字/日期/布尔值。
  • 多行值和数组非标准;若需要可通过 IniMap 结合自定义 reviver/replacer 模拟。
  • 注释以 #;// 开头,IniMap 能保留注释。

示例 Jump to heading

类型强制转换

import * as ini from "@std/ini";

const cfg = ini.parse(text, {
  reviver(key, value) {
    if (/^(true|false)$/i.test(value)) return value.toLowerCase() === "true";
    if (/^\d+$/.test(value)) return Number(value);
    return value;
  },
});

自定义赋值运算符及美化格式化

import * as ini from "@std/ini";

const txt = `name: Deno\nversion: 1`;

// 解析时使用 ':' 替代 '='
const parsed = ini.parse(txt, { assignment: ":" });

// 写出时继续使用 ':' 并进行美化间距
const out = ini.stringify(parsed, { assignment: ":", pretty: true });
// out => "name : Deno\nversion : 1"

使用 IniMap 保留注释和顺序

import { IniMap } from "@std/ini/ini-map";

const text = `# Global
[app]
# 监听端口
port=8080`;

const im = new IniMap();
im.parse(text);

// 修改值同时保留注释和顺序
im.set("app", "port", "9090");

// 输出时保留注释和结构
const roundTrip = im.toString();

合并分层配置(基础 + 本地覆盖)

import { IniMap } from "@std/ini/ini-map";

const baseText = `[db]\nhost=localhost\nport=5432\n[app]\nmode=prod`;
const localText = `[db]\nport=6543\n[app]\nmode=dev`;

const base = new IniMap();
base.parse(baseText);

const local = new IniMap();
local.parse(localText);

// 将本地覆盖的值叠加到基础配置
const overlay = (target: IniMap, source: IniMap) => {
  const obj = source.toObject() as Record<string, unknown>;
  for (const [k, v] of Object.entries(obj)) {
    if (v && typeof v === "object" && !Array.isArray(v)) {
      for (const [kk, vv] of Object.entries(v as Record<string, string>)) {
        target.set(k, kk, vv);
      }
    } else {
      target.set(k, v as string);
    }
  }
};

overlay(base, local);
const merged = base.toString();

重复键:后者覆盖与保留

import * as ini from "@std/ini";
import { IniMap } from "@std/ini/ini-map";

const dup = `x=1\nx=2`;

// 简单解析:以最后一个值为准
const simple = ini.parse(dup); // { x: "2" }

// 使用 IniMap 保留重复键(你可以实现自定义处理)
const im = new IniMap({ deduplicate: true });
im.parse(dup);
// 例如 im.get("x") 默认返回 "2";可利用自定义 reviver 收集所有值

你找到了你需要的东西吗?

编辑此页面
隐私政策