普贤教程 › 基础教程
文件与 IO
文件操作分两层:高层是一行搞定的 read_file / write_file,底层是 open / read / write / close。日常用高层,处理二进制或流才用底层。
高层 API
| 函数 | 作用 | 失败时 |
|---|---|---|
read_file(path) | 读全文为字符串 | 运行时错误 |
read_file_opt(path) | 读全文 | 返回 Err |
write_file(path, text) | 覆盖写入 | 运行时错误 |
append_file(path, text) | 追加写入 | 运行时错误 |
write_bytes(path, b) | 写二进制 | 运行时错误 |
exists(path) | 是否存在 | 返回 bool |
px
write_file("/tmp/px_demo.txt", "第一行\n第二行\n") append_file("/tmp/px_demo.txt", "第三行\n") var text = read_file("/tmp/px_demo.txt") print(text) var lines = split(trim(text), "\n") print("共 " + str(len(lines)) + " 行")
text
第一行
第二行
第三行
共 3 行安全读取
处理"文件可能不存在"的场景,用 read_file_opt,不要先 exists 再读——两步之间有竞态:
px
def safe_read(path): var r = read_file_opt(path) if r.is_err(): return Err("读不到 " + path + ":" + r.err()) return Ok(r.ok()) print(safe_read("/tmp/nope_xyz.txt").err())
text
读不到 /tmp/nope_xyz.txt:io: 读取文件失败 /tmp/nope_xyz.txt: No such file or directory (os error 2)
底层:open / read / write / close
px
var f = open("/tmp/px_low.txt", "w") write(f, "hello\n") close(f) var g = open("/tmp/px_low.txt", "r") var chunk = read(g, 100) close(g) print(bytes_to_str(chunk))
text
hello
read 返回 bytes底层
read 给的是字节串,转文本用 bytes_to_str()。write 接受字符串;写二进制用 write(f, 字节串) 或 write_bytes。用完要 close没有 with 语法,句柄必须显式关。长驻进程里忘记 close 会耗尽文件描述符,表现是"跑几小时后突然打不开文件"。
读标准输入、写标准输出
PuXian 写 CGI 风格的接口时,靠 /dev/stdin 与 /dev/stdout 收发:
px
# 读请求体(二进制安全) var body_in = read_file_opt("/dev/stdin") var body = "" if body_in.is_ok(): body = body_in.ok() # 写响应(必须分块写,见部署一章) var out = open("/dev/stdout", "w") write(out, "Status: 200 OK\n") write(out, "Content-Type: application/json\n") write(out, "\n") write(out, json_stringify({"ok": true, "len": len(body)})) close(out)
二进制不要用 read_file
read_file 遇到 NUL 字节会截断,读图片、zip、编译产物一律用 read_file_opt(或底层 open + read)。遍历目录
目录相关工具在标准库 path 与生态包 dirs / glob 里:
px
import std.path print(path_join("/data/www", "px_dzty_club"))
text
/data/www/px_dzty_club
日志文件写法
px
def log_line(path, msg): var ts = str(now_ms()) append_file(path, ts + "\t" + msg + "\n") log_line("/tmp/px_app.log", "started") log_line("/tmp/px_app.log", "tick") print(read_file("/tmp/px_app.log"))
text
1793869xxx started 1793869xxx tick
日志轮转append 写日志不控大小,长期运行要用 logrotate 或自己在文件超过 N MB 时改名。别让日志把磁盘写满——这是最常见的事故之一。
文件操作的常见失败
| 现象 | 原因 |
|---|---|
| 写入失败 | 父目录不存在、无权限、磁盘满 |
| 读到空内容 | 用了 read_file 读二进制,遇 NUL 截断 |
| 读取内容少一截 | read(f, n) 的 n 给小了,需要循环读 |
| 句柄泄漏 | 异常路径没有 close |