<p>用 seek() 配合 truncate() 生成空洞文件最轻量高效,因不实际写入数据、不占磁盘空间;而 write(b'\x00' * size) 会真实写入并耗时占满磁盘。</p>

直接用 seek() 配合 truncate() 是最轻量、最快生成指定大小空洞文件的方式,不占实际磁盘空间,也不触发写入。
为什么不用 write(b'\x00' * size)?
那会真实写入 size 字节数据,耗时且占满磁盘;而空洞文件(sparse file)只是在文件系统中标记“逻辑上有这么大”,中间未写入区域不分配物理块。
- Linux/macOS 的 ext4、XFS、APFS 原生支持空洞文件;Windows NTFS 也支持,但需注意 Python 运行环境是否启用相关标志
- 用
ls -lsh查看:第一列是实际占用磁盘块数(通常为 0 或极小),第二列才是逻辑大小 -
os.stat(path).st_size返回的是逻辑大小,不是磁盘占用
正确写法:先 seek() 再 truncate()
关键点是不能只靠 seek() —— 它只是移动指针,不改变文件长度;必须调用 truncate() 才能扩展文件到目标位置。
with open('sparse.img', 'wb') as f:
f.seek(1024 * 1024 * 100 - 1) # 跳到 100MiB - 1 字节处
f.write(b'\x00') # 写 1 字节(可选,但确保文件系统创建该位置)
f.truncate(100 * 1024 * 1024) # 显式截断/扩展到 100MiB- 最后一行的
f.truncate(size)是核心:若当前文件长度小于size,就扩展;大于则截断 -
seek()到size - 1后写一个字节,是为了兼容某些旧文件系统或挂载选项(如 ext4 的nosparse),避免truncate()单独调用被忽略 - 如果确定环境支持,可简化为:
f.seek(size - 1); f.write(b'\x00'); f.truncate(size)
常见错误与兼容性陷阱
看似简单,但几个地方容易翻车:
立即学习“Python免费学习笔记(深入)”;
- 用
'w'模式打开 —— 必须用'wb',文本模式下seek()在 Windows 上行为异常 -
truncate()前没write(),在某些 NFS 或容器卷上可能生成 0 字节文件(尤其当初始文件不存在时) - 路径所在文件系统不支持空洞(如 FAT32、某些网络存储、Docker volume 默认驱动),此时会真实写零,速度骤降且占满空间
- Python 3.12+ 对
truncate()的行为更严格,若文件以只读方式打开会抛OSError: [Errno 1] Operation not permitted
空洞文件的“空”是文件系统的契约,不是 Python 的魔法。真正省空间的前提,是你确认底层存储支持 sparse,并且没在中间误触发全量写入 —— 比如日志里不小心循环 write(b'\x00') 就前功尽弃了。


















