ArchiveBox 文件系统工具模块详解:atomic_write 原子写入与 get_dir_size 目录统计

发布时间:2026/9/20 22:22:22
ArchiveBox 文件系统工具模块详解:atomic_write 原子写入与 get_dir_size 目录统计 ArchiveBox 文件系统工具模块详解atomic_write 原子写入与 get_dir_size 目录统计【免费下载链接】ArchiveBox Open source self-hosted web archiving. Takes URLs/browser history/bookmarks/Pocket/Pinboard/etc., saves HTML, JS, PDFs, media, and more...项目地址: https://gitcode.com/gh_mirrors/ar/ArchiveBox本篇文章围绕 ArchiveBox 仓库中的archivebox.misc.system模块展开系统讲解其两个核心工具函数atomic_write与get_dir_size的设计原理、参数语义与实现细节。读者将掌握 ArchiveBox 是如何保证配置文件与索引文件的安全落盘、如何统计归档目录的磁盘占用并理解ENFORCE_ATOMIC_WRITES、OUTPUT_PERMISSIONS等配置项对底层文件写入行为的实际影响从而在自托管部署与二次开发时正确判断文件系统兼容性边界。模块定位Post-bootstrap 文件系统工具archivebox/misc/system.py的模块头注释见 archivebox/misc/system.py明确了两点定位它是Post-bootstrap 文件系统工具提供atomic_write安全原子写入与get_dir_size目录体积统计两个函数它依赖archivebox.config通过get_config读取权限与输出设置因此bootstrap 之前不能安全导入。这决定了该模块在整个 ArchiveBox 中的位置一切需要落盘到主数据目录index.sqlite3、ArchiveBox.conf、JSONL 索引、HTML 索引的写入操作以及需要统计归档体积的命令行工具都以它为底座。与之对应的 API 文档位于 docs/apidocs/archivebox/archivebox.misc.system.md其中公开的模块接口正是这两个函数。atomic_write临时文件 原子重命名的安全写入函数签名与参数语义atomic_write(path: Path | str, contents: dict | str | bytes, overwrite: bool True, configNone, **config_kwargs) - None各参数含义如下参数类型默认值说明pathPath \| str必填目标文件路径支持pathlib.Path与字符串两种形式contentsdict \| str \| bytes必填待写入内容dict会被序列化为 JSONbytes走二进制写str走文本写overwriteboolTrue是否允许覆盖已存在文件透传给底层 atomicwrites 库config配置对象None预取的 ArchiveBox 配置对象为None时用**config_kwargs调用get_config()动态获取**config_kwargs关键字参数—传给get_config()的额外配置覆盖项函数整体由enforce_types装饰实现见 archivebox/misc/util.py 的enforce_types会在运行时依据类型注解校验实参类型非法参数会抛出带函数名、形参名与实际类型的TypeError。写入模式与编码策略函数第一步根据内容类型决定文件模式与编码mode wb if isinstance(contents, bytes) else w encoding None if isinstance(contents, bytes) else utf-8 # enforce utf-8 on all text writesbytes内容以wb二进制模式写入不指定编码文本内容统一强制utf-8编码避免不同平台默认编码差异导致的乱码。三种内容类型的落盘分支写入时按内容类型分派见 archivebox/misc/system.py 第 25-30 行dict使用json.dump(contents, f, indent4, sort_keysTrue, clsExtendedEncoder)序列化——缩进 4 空格、键按字典序排序保证每次写出格式稳定、便于 diffbytes/str直接f.write(contents)。其中ExtendedEncoder是 ArchiveBox 自定义的 JSON 序列化器定义于 archivebox/misc/util.py 的ExtendedEncoder额外支持序列化命名元组_asdict、bytes解码为字符串、datetime转isoformat、Exception、Path转字符串、dict_items/keys/values视图、Callable以及可dict()转换的对象。这意味着atomic_write不仅能写纯文本还能直接写入包含模型字段、时间对象、路径对象的复合dict。原子写入原理atomicwrites 库真正的原子写入由第三方库atomicwrites完成from atomicwrites import atomic_write as lib_atomic_writelib_atomic_write的核心策略是先写入同目录下的临时文件再通过原子重命名atomic rename替换目标文件。这样在任何时刻目标路径要么是旧文件、要么是完整的新文件不会出现写到一半的残缺状态——这正是 ArchiveBox 频繁落盘ArchiveBox.conf、index.json、JSONL 索引等关键文件时防止损坏的基础。OSError 回退机制与ENFORCE_ATOMIC_WRITES原子写入对文件系统有要求需要支持 FSYNC/同步写。当文件系统不支持时如某些网络共享盘、FUSE 挂载lib_atomic_write会抛出OSError此时函数进入回退分支config config or get_config(**config_kwargs) if config.ENFORCE_ATOMIC_WRITES: print(f[X] OSError: Failed to write {path} with fcntl.F_FULLFSYNC. ({e})) print( You can store the archive/ subfolder on a hard drive or network share that doesnt support support synchronous writes,) print( but the main folder containing the index.sqlite3 and ArchiveBox.conf files must be on a filesystem that supports FSYNC.) raise SystemExit(1) # retry the write without forcing FSYNC (aka atomic mode) with open(path, modemode, encodingencoding) as f: ...关键逻辑解读若配置ENFORCE_ATOMIC_WRITESTrue默认值见 archivebox/config/common.py 的StorageConfig直接打印错误并raise SystemExit(1)终止进程。报错信息明确提示archive/子目录可以放在不支持同步写的磁盘上但包含index.sqlite3和ArchiveBox.conf的主目录必须位于支持 FSYNC 的文件系统上若ENFORCE_ATOMIC_WRITESFalse则退化为普通open(path, ...)直接写入放弃原子性保证换取对受限文件系统的兼容。这一设计对自托管部署极具指导意义在 NFS、SMB、某些 FUSE 网盘上运行 ArchiveBox 时若主数据目录写入失败应优先检查该配置项与文件系统类型。权限归一化OUTPUT_PERMISSIONS无论走哪条写入路径函数最后都会统一设置文件权限os.chmod(path, int(config.OUTPUT_PERMISSIONS, base8))OUTPUT_PERMISSIONS是StorageConfig中的字符串配置项默认644见 archivebox/config/common.py按八进制解析后应用到写入文件。这一机制保证了即使进程 umask 或底层库行为不同ArchiveBox 产出的所有文件权限始终与配置一致避免出现其他人可写或不可读的权限混乱。配套地archivebox/config/django.py 在启动时会用os.umask(0o777 - (int(CONFIG.OUTPUT_PERMISSIONS, base8) | 0o111))对齐进程级 umask两者共同作用。get_dir_size递归统计目录体积函数签名与返回值get_dir_size(path: str | Path, recursive: bool True, pattern: str | None None) - tuple[int, int, int]返回三元组(num_bytes, num_dirs, num_files)分别代表返回值含义num_bytes文件总字节数num_dirs目录总数递归模式下统计子目录个数num_files文件总数参数语义参数类型默认值说明pathstr \| Path必填待统计的目录路径recursiveboolTrue是否递归统计子目录False时只统计顶层、遇到子目录直接跳过patternstr \| NoneNone子串过滤条件只统计路径中包含该子串的条目实现要点scandir 递归 容错实现使用os.scandir逐项遍历见 archivebox/misc/system.py 第 55-79 行过滤if (pattern is not None) and (pattern not in entry.path): continuepattern是子串匹配非 glob 通配可用来只统计index.开头的索引文件等特定子集目录处理entry.is_dir(follow_symlinksFalse)判断时不跟随符号链接避免循环链接导致无限递归recursiveFalse时跳过目录recursiveTrue时递归调用自身并累加内部统计文件处理entry.stat(follow_symlinksFalse).st_size取符号链接自身的元数据而非目标累加字节数与文件数容错整个遍历包裹在try/except OSError中遇到FileNameTooLong等读取错误时静默跳过该目录保证统计过程不会因单个异常目录而整体崩溃。实际调用场景archivebox status命令get_dir_size最典型的消费者是archivebox status命令见 archivebox/cli/archivebox_status.py其使用方式充分体现了两个参数的价值索引文件统计get_dir_size(out_dir, recursiveFalse, patternindex.)—— 只扫描顶层目录中路径含index.的文件index.sqlite3、index.json等并显示格式化后的体积全量数据统计对archive_dir递归调用get_dir_size(root)统计全部快照数据当 SQL 索引中的链接数超过MAX_STATUS_FS_DIR_SCAN 5000时则放弃精确扫描改用数据库聚合Sum(output_size)与ArchiveResult.output_files计数来估算避免大规模归档下全盘遍历的开销。在archivebox add命令中它也被用于汇报新增 Crawl 输出目录的大小见 archivebox/cli/archivebox_add.py 第 290 行附近与printable_filesize配合输出人类可读的体积。atomic_write在 ArchiveBox 内部的关键落盘点atomic_write贯穿了 ArchiveBox 所有不能写坏的核心文件主要调用点包括1.ArchiveBox.conf配置文件的镜像与持久化archivebox/config/collection.py 中_write_file_if_changed第 120-136 行仅在内容实际变化时才原子写入ArchiveBox.conf。注释指出跳过无变化写入是把热自动探测循环中每次Machine.save一次磁盘写降为零次的关键优化mirror_machine_config_to_file第 139-153 行将Machine.config扁平化渲染后镜像到配置文件并带递归保护_MIRROR_IN_PROGRESS防止write_config_file → Machine.save来回触发死循环迁移/备份场景第 272-310 行用atomic_write(config_path, CONFIG_FILE_HEADER)写新配置、写.bak备份、写迁移后的配置全程原子。2. JSONL 索引与静态导出文件archivebox/core/models.py 中多处使用atomic_write第 491 行附近写入DATA_DIR / JSONL_INDEX_FILENAMEindex.jsonl清单第 3515 行附近Snapshot导出静态 JSONself.to_dict(extendedTrue, static_exportTrue)第 3683 行附近写入output_dir / HTML_INDEX_FILENAME快照目录内的index.html。这些文件一旦损坏就会导致整个归档索引不可读因此全部通过原子写入保证完整性。配置项速查影响文件写入行为的两个开关两个相关配置项都定义在 archivebox/config/common.py 的StorageConfig中配置项默认值作用OUTPUT_PERMISSIONS644以八进制字符串指定所有输出文件的权限位atomic_write落盘后统一os.chmod应用ENFORCE_ATOMIC_WRITESTrue强制要求原子写依赖 FSYNCFalse时在原子写失败后回退为普通写入部署建议在主数据目录所在文件系统不支持 FSYNC如部分网络/共享文件系统时可评估ENFORCE_ATOMIC_WRITESFalse以换取兼容性但应意识到这削弱了崩溃一致性保证官方错误提示明确建议优先保证index.sqlite3与ArchiveBox.conf所在主目录位于支持 FSYNC 的磁盘上archive/数据子目录则可放宽要求。实战在 ArchiveBox 代码中直接使用这两个函数在 ArchiveBox 的插件或扩展代码中需在 bootstrap 之后、archivebox.config可用时导入可以这样复用from pathlib import Path from archivebox.misc.system import atomic_write, get_dir_size # 1. 原子写入一个带权限控制的 JSON 清单 atomic_write( Path(/path/to/manifest.json), {snapshots: 10, updated_at: 2026-09-19T05:00:08}, OUTPUT_PERMISSIONS600, ) # 2. 只统计顶层 index.* 文件不递归 bytes_, dirs, files get_dir_size(/path/to/archive, recursiveFalse, patternindex.) print(findex files: {files}, total bytes: {bytes_}) # 3. 递归统计整个归档体积 total_bytes, total_dirs, total_files get_dir_size(/path/to/archive)注意atomic_write的**config_kwargs可直接以关键字形式传入配置覆盖项如OUTPUT_PERMISSIONS函数内部会据此构造配置对象。小结archivebox.misc.system是 ArchiveBox 文件持久化层的安全底座atomic_write用临时文件 原子重命名策略保护ArchiveBox.conf、JSONL/JSON/HTML 索引等关键文件配合ENFORCE_ATOMIC_WRITES的强制/回退双模式与OUTPUT_PERMISSIONS的权限归一化在数据安全与文件系统兼容性之间提供了明确的取舍开关get_dir_size基于os.scandir实现高效目录统计支持递归、子串过滤与符号链接隔离并内置OSError容错是archivebox status、archivebox add展示归档体积的核心依据。理解这两个函数及其背后配置有助于判断自托管部署中哪些目录必须放在支持 FSYNC 的磁盘上、归档体积统计的精确/估算切换条件以及如何安全地在扩展代码中写入 ArchiveBox 的关键索引文件。【免费下载链接】ArchiveBox Open source self-hosted web archiving. Takes URLs/browser history/bookmarks/Pocket/Pinboard/etc., saves HTML, JS, PDFs, media, and more...项目地址: https://gitcode.com/gh_mirrors/ar/ArchiveBox创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考