前两篇把目标与上下文准备好了,这次让 Codex 交付一个能运行的小程序:读取 input/ 第一层的小写 .txt 文件,生成两列CSV清单。文件内容保持原样,输出能与实际文件逐项对照。
前置条件与本篇目标
沿用三份合成文本、任务卡和 codex-learning 目录。本例在Windows、Python 3.10.6中执行,使用标准库,不需要安装第三方包。跟做前先确认你已有可运行的Python 3.10或更高版本;未找到解释器时,先让 Codex 说明环境缺口,不把安装失败当作脚本失败。
本篇只做第一版清单,不递归、不删除文件、不分析文本内容。默认输出固定为 output/file-list.csv;再次运行会重写这份生成文件,输入不变。
资料核对日期:2026年11月4日。官方提示指南强调讲清行为、相关文件、约束以及验证方法;本篇用第03篇任务卡落实这些信息,不要求先安装额外插件。官方提示指南
1. 给 Codex 一条可以验收的请求
先读取 TASK.md,确认当前项目和Python解释器。根据任务卡编写 file_list.py。
扫描脚本所在目录下 input/ 第一层的普通、小写 .txt 文件,不递归,不跟随链接或Windows重解析点。
生成 output/file-list.csv,表头为 relative_path,size_bytes。
路径相对项目、使用 /,大小来自实际文件字节数,按相对路径排序。
输入只读;仅创建脚本与指定输出。不安装第三方依赖,不删除、改名或上传输入。
输入目录缺失时明确失败,不能当成成功处理0个文件。
完成后实际运行,报告命令、退出码、输出内容和未验证的情况。
注意,这次明确授权了脚本与CSV的创建;上一篇“只读材料、不创建程序”的任务范围没有被含糊地沿用。
2. 第一版完整代码
下面是本例实际执行的 file_list.py。将它放在与 input 同一级的位置:
import csv
import stat
import sys
from pathlib import Path
def is_link_or_reparse(path):
try:
info = path.lstat()
except FileNotFoundError:
return False
return stat.S_ISLNK(info.st_mode) or bool(
getattr(info, "st_file_attributes", 0)
& getattr(stat, "FILE_ATTRIBUTE_REPARSE_POINT", 0)
)
def build_list(root):
source = root / "input"
if is_link_or_reparse(source) or not source.is_dir():
raise ValueError("input 必须是存在的普通目录")
rows = []
for item in source.iterdir():
if is_link_or_reparse(item):
continue
if item.is_file() and item.suffix == ".txt":
rows.append((item.relative_to(root).as_posix(), item.stat().st_size))
rows.sort(key=lambda row: row[0])
output_dir = root / "output"
destination = output_dir / "file-list.csv"
if is_link_or_reparse(output_dir) or is_link_or_reparse(destination):
raise ValueError("输出位置不能是链接或重解析点")
output_dir.mkdir(exist_ok=True)
with destination.open("w", encoding="utf-8", newline="") as stream:
writer = csv.writer(stream)
writer.writerow(["relative_path", "size_bytes"])
writer.writerows(rows)
return len(rows)
if __name__ == "__main__":
try:
count = build_list(Path(__file__).resolve().parent)
except (OSError, ValueError) as error:
print(f"失败:{error}", file=sys.stderr)
raise SystemExit(2)
print(f"已生成 output/file-list.csv,共 {count} 条数据")
Path(__file__).resolve().parent把本例的输入位置固定在脚本所在目录。st_size读取字节数,中文字符数不能代替它。newline=""把CSV换行交给标准库处理。
代码先收集记录,再写指定输出。它检查链接与Windows重解析点,但这不是操作系统级沙箱;并发替换、复杂权限和全部文件系统行为不在本次验证范围。
3. 运行并打开结果
在练习目录中,使用已确认的Python解释器运行:
python -I -B -X utf8 file_list.py
如果你机器上使用的是其他解释器命令或完整路径,就替换开头的 python。本例实际运行的退出码为0,输出为:
已生成 output/file-list.csv,共 3 条数据
打开CSV可以看到:
relative_path,size_bytes
input/01-学习计划.txt,90
input/02-待办清单.txt,82
input/03-复盘记录.txt,94
这些大小来自本例实际文件。你自己保存文本时,如果换行或编码不同,字节数可能不同;应与自己的文件核对,不能为了匹配90、82、94去修改程序或输入。
4. 本次实际验证的结果
| 检查 | 实际结果 |
|---|---|
| 三份样例的表头、路径、大小与顺序 | 与实际文件一致,3条数据,不把表头计作数据 |
| 再次运行 | CSV逐字节一致 |
| 原输入前后比较 | 三份输入SHA-256不变 |
| input目录缺失 | 退出码2,没有生成CSV |
| input为空 | 退出码0,仅有表头 |
| 混入Markdown与含txt的子目录 | 只得到第一层keep.txt一条记录,未递归 |
这6项检查均已实际运行,使用的都是项目内合成样例,没有调用额外模型API。真实符号链接/目录联接夹具、并发文件替换、大目录性能、权限错误和所有系统版本尚未实测,不把代码中的分支当作已经覆盖。
常见错误与验收方法
看到 input 必须是存在的普通目录,先核对脚本位置和同级目录;本例不会自动猜测其他目录。得到0条数据时,检查第一层是否确有小写 .txt 文件:Markdown、.TXT和子目录中的文件不属于当前约定。
如果只得到了代码、没有实际运行结果,要求 Codex 使用确认过的解释器运行,并展示退出码与CSV。运行失败时保留报错,先复现原因,不把“代码看起来可以”写成完成。
最后打开实际CSV,逐条定位输入,核对大小,再检查输入是否变化。到这里,你已经有了第一版可核对的小工具。下一篇学习看懂修改差异,并给这份工作留一个恢复点。
示例已编写并验证。创作说明:AI 辅助创作。