> ## Documentation Index
> Fetch the complete documentation index at: https://ahvn.top/llms.txt
> Use this file to discover all available pages before exploring further.

# 文件系统

> 通过 pj 实现可移植路径，以及面向本地产物的配置驱动序列化。

<Note>
  *好记性不如烂笔头。*
</Note>

当 demo、测试、脚本或扩展需要可预测的本地文件，而不想手写路径处理与序列化细节时，请使用本页。文件系统工具围绕两个核心：**`pj(...)`** 用于可移植路径，以及 **序列化家族 (serialization family)** —— 在 JSON、YAML、文本、JSONL、jstr、二进制等相关格式上实现一致的读写。

<br />

## 1. 为何需要统一的文件系统工具

若没有统一的文件系统工具，每个脚本与 demo 都会重新实现路径拼接、别名解析、编码处理与序列化，结果不一致：一个模块用 `os.path.join(...)` 搭配硬编码相对路径，另一个用 `pathlib.Path` 与 `expanduser()`，第三个硬编码在 Windows 上会失效的 `/` 分隔符。序列化同样会各自为政 —— 一个调用方用 `indent=2` 写 JSON，另一个用 `default=str`，第三个硬编码 `utf-8` 编码。

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Anti-pattern: every caller handles paths differently
import json
import os

demo_dir = os.path.join(os.path.expanduser("~"), "heavenbase-demo", "data")
config_path = "../config.yaml"  # breaks depending on working directory
cache_dir = "C:/Users/me/.cache/heavenbase/" if os.name == "nt" else "/home/me/.cache/heavenbase"

with open(os.path.join(demo_dir, "meta.json"), "w", encoding="utf-8") as handle:
    json.dump({"rows": 3}, handle, indent=2, default=str)
```

HeavenBase 将路径与序列化视为成对的基础设施。**`pj(...)`** 是统一的路径词汇：展开 `~`、解析环境变量、规范化分隔符、可选返回绝对路径，并解析调用方提供的别名。**序列化家族** 使用配置驱动的默认值（`CM_HVNB` 中的 `heavenbase.serialize.encoding` 与 `heavenbase.serialize.indent`），让各调用方无需重复这些参数即可获得一致输出。

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import dump_json, pj

# Portable paths and consistent serialization in one flow
project_root = pj(".", abs=True)
cache_file = pj("~/heavenbase-cache", "index.json", abs=True)
run_path = pj("%/runs/latest.json", aliases={"%": "demos/.temp"}, abs=True)

dump_json({"workspace": "docs-demo", "rows": 3}, run_path, sort_keys=True)
```

两者同等重要：先用 `pj(...)` 构建路径，再通过匹配的序列化 helper 读写，无需重复指定编码、缩进或平台细节。

<br />

## 2. 两个核心思想

文件系统工具清晰分为路径词汇与序列化 I/O。本页其余内容 —— 创建文件夹、列出文件、复制产物、文件夹结构图 —— 均服务于这两条主线。

### 2.1. `pj(...)` — 可移植路径

`pj(...)` 是规范的路径拼接 helper。它拼接路径片段、展开 `~` 与环境变量、规范化分隔符、可选返回绝对路径，并可解析调用方提供的别名。

可将其视为一套小型路径词汇。`.` 表示当前工作位置，`~` 展开为用户主目录，环境变量通过操作系统展开，而 `%` 或 `&` 等别名可在调用方或配置管理器提供别名映射时指向包数据文件夹或资源文件夹。

<Info>
  工具 `pj(...)` 处理普通路径与调用方别名。`CM_HVNB.pj(...)` 处理 HeavenBase 包别名：`%/` 表示包本地数据，`&/` 表示包资源。
</Info>

<br />

### 2.2. 序列化家族 — 配置驱动的 I/O

序列化 helper 封装常见读写，原因与配置封装超参数相同：调用方不应在每个函数中传递编码、缩进与平台路径细节。

每种格式暴露相同的命名模式：

| Prefix                | Scope                      | Example                     |
| --------------------- | -------------------------- | --------------------------- |
| `loads_*` / `dumps_*` | In-memory strings or bytes | `dumps_json({"rows": 3})`   |
| `load_*` / `dump_*`   | File read/write            | `dump_json(obj, path)`      |
| `save_*`              | Alias of `dump_*`          | `save_txt("# Notes", path)` |
| `append_*`            | Append one record or line  | `append_jsonl(event, path)` |

文本编码默认为 `heavenbase.serialize.encoding`，在默认配置中为 `utf-8`。JSON 与 YAML 缩进默认为 `heavenbase.serialize.indent`，值为 `4`。缺失文件返回空默认值（`""`、`{}`、`[]` 或 `b""`），除非传入 `strict=True`。这里展示了配置驱动方法的好处：你可以更改默认编码或缩进，而无需更改每个调用方。

JSON helper 使用 `HbJsonEncoder` 与 `HbJsonDecoder`，保留 datetime、Decimal、元组、集合与 callable 引用等常见 HeavenBase 值 —— 产物可往返而无需临时 `default=str` 处理器。

<br />

## 3. 构建路径

对普通本地路径使用 `pj(...)`：

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import pj

project_root = pj(".", abs=True)
cache_file = pj("~/heavenbase-cache", "index.json", abs=True)
```

当第一段路径是项目专用快捷方式时，传入别名：

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import pj

run_path = pj("%/runs/latest.json", aliases={"%": "demos/.temp"}, abs=True)
asset_path = pj("&/sample.txt", aliases={"&": "demos/assets"}, abs=True)
```

通过配置管理器使用包别名：

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import CM_HVNB

config_db = CM_HVNB.pj("%/config.db", abs=True)
default_yaml = CM_HVNB.pj("&/configs/default.yaml", abs=True)
```

<br />

## 4. 准备文件与文件夹

写入产物前使用 `touch_dir(...)` 与 `touch_file(...)`。两者都会创建缺失的父目录并返回绝对路径。

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import exists_file, touch_dir, touch_file

root = touch_dir("demos/.temp/report")
summary = touch_file(f"{root}/summary.md", content="# Summary")

assert exists_file(summary)
```

仅当文件夹或文件应从空状态开始时，才使用 `clear=True`：

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import touch_dir

run_dir = touch_dir("demos/.temp/run", clear=True)
```

<br />

## 5. 读写数据

序列化是本页的第二根支柱。选定格式、调用匹配的 helper，让 `CM_HVNB` 提供编码与缩进默认值。结合 `pj(...)` 与 `touch_dir(...)` 即可完成完整的产物工作流。

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import append_jsonl, dump_json, load_json, pj, save_txt, touch_dir

root = touch_dir(pj("demos", ".temp", "docs-run"))
meta_path = pj(root, "meta.json")

dump_json({"workspace": "docs-demo", "rows": 3}, meta_path, sort_keys=True)
save_txt("# Run Notes", pj(root, "notes.md"))
append_jsonl({"event": "created", "path": meta_path}, pj(root, "events.jsonl"))

meta = load_json(meta_path)
```

### 5.1. JSON

JSON 适用于结构化、机器可读的产物 —— 配置、运行元数据、工作区 (Workspace) 快照，以及与其他工具的交换。

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import dump_json, dumps_json, load_json, loads_json

payload = {"workspace": "docs-demo", "items": (1, 2)}  # tuples round-trip
text = dumps_json(payload, sort_keys=True, compact=True)
restored = loads_json(text)

dump_json(payload, "demos/.temp/docs-run/meta.json", sort_keys=True)
assert load_json("demos/.temp/docs-run/meta.json")["items"] == (1, 2)
```

需要确定性键序时（例如哈希前）传入 `sort_keys=True`。需要单行输出时传入 `compact=True` 或 `indent=None`。

<br />

### 5.2. YAML

YAML 适用于人类可编辑的结构化文件，例如配置模板与小型清单。

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import dump_yaml, dumps_yaml, load_yaml

spec = {"model": "demo", "batch_size": 8}
dump_yaml(spec, "demos/.temp/docs-run/spec.yaml")
assert load_yaml("demos/.temp/docs-run/spec.yaml")["batch_size"] == 8
```

YAML 通过 `heavenbase.serialize.indent` 与 JSON 共享相同的缩进默认值。

<br />

### 5.3. 文本

文本 helper 适用于日志、Markdown 笔记、纯文本报告，以及任何人可读的行式输出。

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import append_txt, load_txt, save_txt

save_txt("# Run Notes\n", "demos/.temp/docs-run/notes.md")
append_txt("event: created", "demos/.temp/docs-run/log.txt")
notes = load_txt("demos/.temp/docs-run/notes.md")
```

`load_txt` 在文件缺失时返回 `""`，除非 `strict=True`。`append_txt` 在每次写入后追加换行符。

<br />

### 5.4. JSONL

当工作流逐条追加事件或记录时使用 JSONL —— 运行日志、流式导出与增量审计轨迹。

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import append_jsonl, dump_jsonl, iter_jsonl, load_jsonl

append_jsonl({"event": "created", "idx": 1}, "demos/.temp/docs-run/events.jsonl")
append_jsonl({"event": "updated", "idx": 2}, "demos/.temp/docs-run/events.jsonl")

rows = load_jsonl("demos/.temp/docs-run/events.jsonl")
for row in iter_jsonl("demos/.temp/docs-run/events.jsonl"):
    print(row["event"])
```

增量写入优先用 `append_jsonl`；完整可迭代对象在内存中时用 `dump_jsonl`。大文件用 `iter_jsonl` 流式读取，无需一次加载所有行。

<br />

### 5.5. jstr — 面向 Python 的文本

**jstr** 表示「顶层值为容器时用 JSON，否则用字符串」。在 Tool 结果、memstate 行与 MCP 载荷等文本边界处使用 `dumps_jstr`、`loads_jstr`、`dump_jstr`、`load_jstr` 与 `save_jstr`，让结构化值保持机器可读，标量与其他值通过 `str(...)` 保持人类可读。

规则：

* 顶层 `dict` 或 `list` 值（含嵌套容器）通过与 `dumps_json` 相同的编码器序列化为紧凑 JSON。
* 所有其他值，包括 `int`、`float`、`bool`、`None`、元组、集合与自定义对象，均使用 `str(obj)`。
* `loads_jstr` 解析形如 JSON 对象或数组的文本；该形态下的无效 JSON 以及所有其他文本，均原样作为字符串返回。

工具集 (Toolkit) 与 MCP 边界默认使用此格式。每个 Tool 保持 `serializer=None`，在执行时解析为共享的 `jstr_serializer` Capsule，因此 `toolkit.run_to_str(...)` 与 FastMCP 服务会将成功的工具输出路由到 `dumps_jstr`。本地 Python 调用方仍可使用 `toolkit.run(...)` 获取原始对象。

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import dumps_jstr, loads_jstr, save_jstr

assert dumps_jstr(42) == "42"
assert dumps_jstr({"rows": 3, "items": [{"id": 1}]}) == '{"rows": 3, "items": [{"id": 1}]}'
assert loads_jstr('{"rows": 3}') == {"rows": 3}
assert loads_jstr("plain note") == "plain note"

save_jstr({"event": "created"}, "demos/.temp/docs-run/events.jstr")
```

<br />

### 5.6. 二进制

二进制 helper 适用于原始字节载荷 —— 模型权重、压缩 blob、图像字节及其他非文本产物。

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import dump_bin, load_bin, save_bin

payload = b"\x00\x01\x02"
save_bin(payload, "demos/.temp/docs-run/blob.bin")
assert load_bin("demos/.temp/docs-run/blob.bin") == payload
```

`load_bin` 在文件缺失时返回 `b""`，除非 `strict=True`。

<br />

### 5.7. Hex 与 Base64

当字节载荷需要在文件或日志中以文本安全形式表示时，使用 hex 与 Base64 helper。

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import dump_b64, dump_hex, load_b64, load_hex, dumps_b64, loads_b64

raw = b"hello"
assert loads_b64(dumps_b64(raw)) == raw

dump_hex("48656c6c6f", "demos/.temp/docs-run/hello.hex")
assert load_hex("demos/.temp/docs-run/hello.hex") == "48656c6c6f"

dump_b64(dumps_b64(raw), "demos/.temp/docs-run/hello.bin")
assert load_b64("demos/.temp/docs-run/hello.bin") == dumps_b64(raw)
```

`dump_hex` 与 `dump_b64` 解码 hex 或 Base64 字符串并写入结果字节。`load_hex` 与 `load_b64` 读取二进制文件并返回 hex 或 Base64 文本表示。内存编码不触及文件系统时使用 `dumps_b64` / `loads_b64`。

<br />

### 5.8. Pickle

请仅对由你自身环境产生的可信本地产物使用 pickle。加载 pickle 可能执行任意代码，绝不可跨越信任边界。

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import dump_pkl, load_pkl

state = {"cache": {"rows": 3}}
dump_pkl(state, "demos/.temp/docs-run/state.pkl")
assert load_pkl("demos/.temp/docs-run/state.pkl") == state
```

<Warning>
  `load_pkl(...)` 读取 Python pickle 数据。请仅对由你自身环境产生的可信本地产物使用 pickle。
</Warning>

<br />

## 6. 列出、复制与删除产物

`list_files(...)` 读取直接子项。`enum_files(...)` 递归遍历。两者均返回稳定、不区分大小写的顺序。

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import copy_path, delete_path, enum_files, list_files

for name in list_files("demos/.temp/docs-run", ext="json"):
    print(name)

for path in enum_files("demos/.temp/docs-run", ext=["json", "jsonl"], abs=True):
    print(path)

copy_path("demos/.temp/docs-run", "demos/.temp/docs-run-copy", mode="merge")
delete_path("demos/.temp/docs-run-copy")
```

复制 helper 使用显式冲突模式。文件支持 `replace`、`skip` 与 `strict`；目录还支持 `merge`。

<br />

## 7. 显示文件夹结构图

在日志、报告与文档片段中使用 `folder_diagram(...)` 做紧凑诊断。

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from heavenbase.utils import folder_diagram

print(folder_diagram("demos/.temp/docs-run", annotations={"meta.json": "run metadata"}, limit=12))
```

<Warning>
  `delete_dir(...)` 与 `delete_path(...)` 会删除本地数据。请将 demo 清理目标限制在 `demos/.temp/` 等已知临时文件夹下。
</Warning>

<br />

## 进一步探索

<Tip>
  **相关资源：**

  * [配置](/zh/features/configuration) - 序列化 helper 使用的配置驱动默认值。
  * [哈希](/zh/features/utilities/hash) - 确定性的文件安全标识符与指纹。
  * [杂项](/zh/features/utilities/miscs) - 围绕本地产物的命令执行。
</Tip>

<br />
