# 文件系统
`fs/` 命名空间是标准库的整文件与路径层:读取、写入、列出、检视和监视
文件与目录。它被编译进每个运行时,无需导入。前导段命名了 VFS 挂载的
路径会路由到该挂载的驱动,而非原生文件系统 —— 参见
VFS。对于已打开文件上的面向行 I/O(而非整文件
读写),请使用 I/O 中的裸通道函数 `open`、`puts`、`gets` 和 `close`。
读取、stat 与列表调用还会解析 导入/包路径:当某个前导段命名了导入
挂载(例如 `deft/help/manual/01-Language/...`)的路径不作为字面路径存在
时,它会通过与 `import`/`import/resolve` 相同的探测流程解析 —— 包括
`src/` 旁边的包根资产,如 `manual/` 和 `docs/`。因此同一逻辑路径在
任何工作目录下都能工作,无论是在开发检出还是已安装的包树中;已存在的
原生路径始终优先。
## 函数
### 读取与写入
| 函数 | 用途 |
|---|---|
| `fs/read "path"` | 以字符串读取文件内容:`%Ok{:value "..."}`;失败时返回 `%Err` |
| `fs/write "path" "content"` | 将字符串写入文件,创建或截断该文件(`%Ok{:value true}` / `%Err`) |
| `fs/append "path" "content"` | 将字符串追加到文件(`%Ok{:value true}` / `%Err`) |
| `fs/read-lines "path"` | 将文件读取为 `%Ok` 行向量(末尾换行符不算额外一行) |
| `fs/write-lines "path" @{...}` | 写入行向量,每行一个换行符(`%Ok{:value true}` / `%Err`) |
| `fs/copy "from" "to"` | 复制文件;成功时返回 `%Ok{:value true}`(读 + 写,因此可跨 VFS 挂载组合) |
| `fs/rename "from" "to"` | 重命名或移动文件(`%Ok{:value true}` / `%Err`;同一挂载内) |
| `fs/remove "path"` | 删除文件或空目录(`%Ok{:value true}` / `%Err`) |
| `fs/link "target" "link-path"` | 在 `link-path` 创建指向 `target` 的符号链接(`%Ok{:value true}` / `%Err`;仅原生) |
| `fs/mkdir "path"` | 创建目录及所有缺失的父目录;幂等(`%Ok{:value true}` / `%Err`) |
### 元数据与谓词
| 函数 | 用途 |
|---|---|
| `fs/exists? "path"` | 路径存在时为 true |
| `fs/file? "path"` | 路径存在且不是目录时为 true |
| `fs/dir? "path"` | 路径是目录时为 true |
| `fs/absolute? "path"` | 绝对路径和挂载锚定路径为 true |
| `fs/stat "path"` | `%Ok` 包装的 `%{ :size N :is-dir bool :modified ms }` —— mtime 为 epoch 毫秒 |
| `fs/list "path"` | `%Ok` 包装的 `%{ :name str :is-dir bool :kind str }` 条目向量 |
| `fs/readdir "path"` | `%Ok` 包装的仅条目名称(字符串)向量 |
| `fs/glob "path" "pattern" ?opts` | 基名匹配 `*`/`?` 的文件,以 `%Ok` 包装的 `%{ :path dir :file name }` 映射表示;`%{ :recurse true }`(或 `--recurse`)遍历子目录 |
### 路径辅助函数
| 函数 | 用途 |
|---|---|
| `fs/join "a" "b" ...` | 用 `/` 连接各组成部分 |
| `fs/abs "path"` | 绝对路径;挂载锚定路径原样通过 |
| `fs/dir "path"` | 目录部分(没有时为 `"."`) |
| `fs/base "path"` | 文件名部分 |
| `fs/ext "path"` | 含点号的扩展名(`.txt`),没有时为空 |
### 主机路径与临时路径
| 函数 | 用途 |
|---|---|
| `fs/tempdir` | 系统临时目录(`$TMPDIR`,否则 `/tmp`) |
| `fs/home` | 主目录(`$HOME`;未设置时为 `nil`) |
| `fs/tmp-dir` | 每进程临时目录 `/tmp/deft-<pid>/`,首次调用时创建 |
| `fs/tmp-path ?file` | 临时目录,或给定文件名时其中的一个路径 |
| `fs/local-path "sub" "file"` | 约定路径 `.deft/local/<sub>/<file>`;不会创建目录 |
| `fs/local-dir "sub"` | `.deft/local/<sub>`,需要时(连同父目录)创建;幂等 |
### 监视
| 函数 | 用途 |
|---|---|
| `fs/watch "path" callback` | 监视文件或目录(递归)并返回 `%Ok` 包装的数字 watch-id |
| `fs/unwatch $id` | 取消监视;移除监视时返回 true |
说明:
- 整文件动词成功时返回 `%Ok{:value ...}`,失败时返回
`%Err{:message}`:数据动词包装其载荷(`%Ok{:value "..."}`、
`%Ok{:value list}`),变更动词包装 `true`(`%Ok{:value true}`)。
用 `ok!`、`unwrap`、`match` 或 `err?` 解包 —— 或使用谓词
(`fs/exists?`、`fs/file?`、`fs/dir?`、`fs/absolute?`),它们返回
布尔值。
- `fs/watch` 用标志关键字 —— `:created`、`:modified` 或 `:removed` ——
和变更路径调用其回调。处理函数仅在事件循环泵送时触发(`vwait`、
`update`、服务器),与 `[after]` 和网络回调的契约相同。
- VFS 路由适用于整文件动词和元数据调用;`fs/watch`、`fs/link` 和递归
`fs/glob` 仅限本地。主机路径辅助函数(`fs/tempdir`、`fs/home`、
`fs/tmp-dir`、`fs/tmp-path`、`fs/local-path`、`fs/local-dir`)按设计
保持主机本地。详情见 VFS。
## 示例
### 写入并读取文件
def path "/tmp/deft-notes/notes.txt" fs/mkdir [fs/dir $path] fs/write $path "first line\nsecond line\n" echo "contents:" [unwrap [fs/read $path]] each [unwrap [fs/read-lines $path]] {|line| echo "line:" $line }
### 列出目录
each [unwrap [fs/readdir "packages/help/docs"]] {|name| echo $name } for entry in [unwrap [fs/list "packages/help/docs"]] { echo $entry~name "dir?" $entry~is-dir "kind" $entry~kind }
`fs/readdir` 只给出名称;`fs/list` 给出 `%{ :name :is-dir :kind }`
映射。`fs/glob` 按基名搜索,且可以递归:
def hits [unwrap [fs/glob "packages/help/manual" "*.md" %{ :recurse true }]] each $hits {|hit| echo [fs/join $hit~path $hit~file] }
### 用 fs/join 构建路径
set root [fs/tempdir] set out [fs/join $root "deft-exports" "report.txt"] echo "dir:" [fs/dir $out] "base:" [fs/base $out] "ext:" [fs/ext $out] # dir: /tmp/deft-exports base: report.txt ext: .txt
### 监视目录
def wid [unwrap [fs/watch "www" {|flag file| echo $flag $file }]] # ... the event loop runs (vwait / sleep / server) ... [fs/unwatch $wid]