全部章节21
本页目录

指南 · 第 4 章

文件与路径

遍历目录、读取文本并安全写入结果。

1.7.1 受控并发与原子性

本版修复资源生命周期并交付七个默认关闭的实验接口。请先了解状态所有者、协作文件锁、严格事务以及有界任务的保证边界。

阅读完整指南与示例包含保证矩阵、错误处理和实际验收证据

Path 不是 String

所有文件 API 都要求 Path。path(text) 做词法规范化:折叠重复分隔符和 .,消除可以解析的 ..,但不访问文件系统也不解析符号链接。相对 Path 始终基于进程启动目录,不随被 import 的文件位置变化。

example.hhy
let source = path("./src/../src/main.c")
let target = path_join(source.parent, "runtime.c")

print(source)
print(source.name)
print(source.extension)
print(source.parent)
print(target)

name、extension、parent 是 Path 的只读字段,不是 path_name()、path_extension()、path_parent() 函数。extension 包含前导点,无扩展名时为空字符串;path_join(base, child) 返回组合后的新 Path。

files:遍历、glob 与元数据

example.hhy
path("./logs")
    |> files("**/*.log")
    |> where { file -> file.size > 1mib }
    |> flat_map { file -> read_lines(file.path) }
    |> where { line -> contains(line, "ERROR") }
    |> save_lines(path("errors.txt"))

files(root, pattern, options?) 返回惰性的 Stream<File | Directory>,不会返回遍历根本身。pattern 支持 *、?、**;默认不跟随目录符号链接,{ follow_symlinks: true } 可开启并自动跳过检测到的目录循环。

字段含义
path完整 Path
name文件或目录名
extension包含前导点的扩展名
sizeBytes 大小
created创建时间;不可可靠取得时为 null
modified修改时间
is_file / is_dir / is_symlink对象种类标记

File 和 Directory 是系统对象,不是 Map。写入 JSON 前,先把需要的字段映射成普通 Map。

读取文本与二进制

函数read_text#

read_text(Path) -> String

完整读取 UTF-8 文件为 String。

函数read_lines#

read_lines(Path) -> Stream<String>

逐行惰性读取 UTF-8 文件并移除行终止符。

函数read_bytes#

read_bytes(Path) -> BytesBuffer

完整读取二进制文件为 BytesBuffer。

写入、追加与原子保存

example.hhy
let input = path("notes.txt")
let backup = path("backup-notes.txt")

write_text(input, "first line\n", { overwrite: true })
append_text(input, "second line\n")
copy(input, backup, { overwrite: false })

read_lines(backup)
    |> map { line -> upper(line) }
    |> save_lines(path("backup/upper.txt"), { create_parents: true })

函数write_text#

write_text(Path, String, Map?) -> Path

以原子替换方式写 String,支持 overwrite/create_parents。

函数append_text#

append_text(Path, String) -> Path

把 String 追加到文件末尾。

函数write_bytes#

write_bytes(Path, BytesBuffer, Map?) -> Path

以原子替换方式写 BytesBuffer。

函数save_text#

save_text(String | Stream<String>, Path, Map?) -> Path

把 String 或文本 Stream 边拉取边原子保存。

函数save_lines#

save_lines(Stream<String>, Path, Map?) -> Path

把 String Stream 逐项写入并补 LF,最终原子替换。

write_text、write_bytes、save_text、save_lines 的 options 支持 overwrite(默认 true)和 create_parents(默认 false)。这些 API 通过同目录临时文件加 rename 提交;overwrite: false 使用原子 no-replace,避免先检查后写入的竞态覆盖。

复制、移动、删除与 dry-run

函数copy#

copy(Path, Path, Map?) -> Path

复制文件,支持原子 no-replace;目标父目录须预先存在。

函数move#

move(Path, Path, Map?) -> Path

移动或重命名文件,遵守覆盖选项。

函数remove#

remove(Path) -> Path

删除明确 Path,并返回该 Path。

sh
hhy run --dry-run backup.hhy
hhy run backup.hhy

copy 和 move 的目标父目录须预先存在,当前 1.7.1 不处理它们的 create_parents 选项。示例使用 overwrite: false,重复运行前请改用新的备份文件名。先检查 dry-run 计划,再执行包含复制、移动或删除的脚本。

查阅完整 API

路径与文件 API Reference →查阅全部签名、参数形式和函数锚点。