Python os.splice 怎样在文件描述符之间传输数据
如果目标是在 Linux 上把一个文件描述符的数据交给另一个文件描述符,os.splice 的关键不是把数据读进 Python 的 bytes,而是让内核在文件描述符之间完成转移。实际使用时至少要准备一端为管道:先把源文件 splice 到管道写端,再把管道读端 splice 到目标文件。
官方地址:https://docs.python.org/3/library/os.html#os.splice
调用时要记住三件事:返回值是本次实际传输的字节数,短传输必须继续循环;返回 0 表示输入端结束;管道对应的偏移量必须传 None。os.splice 从 Python 3.10 提供,官方文档标注的系统可用范围是 Linux。
先看清 os.splice 的传输模型
os.splice(src, dst, count, offset_src=None, offset_dst=None, flags=0) 的参数顺序是源描述符、目标描述符、本次最多传输的字节数、源偏移、目标偏移和 flags。它不是“两个普通文件直接互拷”的通用包装:至少有一个描述符必须指向管道,普通文件到普通文件的调用不符合这个接口的约束。

因此,常见的文件复制拓扑是“源文件 → 管道写端 → 管道读端 → 目标文件”。中间的管道不是为了让 Python 代码手工搬运数据,而是满足 splice 的内核传输路径,同时把一次大传输拆成可控制的块。
用管道连接源文件和目标文件
下面的示例把源文件按块送入管道,再从管道读端送入目标文件。代码只展示调用结构和错误处理约定,不把任何静态图或示例描述当作本机运行结果。
import os
CHUNK_SIZE = 1024 * 1024
def splice_copy(source: str, target: str) -> int:
source_fd = target_fd = pipe_read = pipe_write = None
total = 0
try:
# 源文件只读,目标文件不存在时创建并在开始时截断。
source_fd = os.open(source, os.O_RDONLY)
target_fd = os.open(
target,
os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
0o644,
)
# 管道让两次 splice 都满足“至少一端是 pipe”的约束。
pipe_read, pipe_write = os.pipe()
while True:
# 从源文件进入管道;None 表示使用并更新源文件当前位置。
moved_to_pipe = os.splice(source_fd, pipe_write, CHUNK_SIZE)
if moved_to_pipe == 0:
break
remaining = moved_to_pipe
while remaining:
# 从管道进入目标文件;管道一端不能传显式 offset。
moved_to_target = os.splice(pipe_read, target_fd, remaining)
if moved_to_target == 0:
raise OSError("管道没有完成预期的输出")
remaining -= moved_to_target
total += moved_to_target
return total
finally:
# 无论成功、EOF 还是异常,都关闭本次创建的全部描述符。
for fd in (pipe_read, pipe_write, source_fd, target_fd):
if fd is not None:
os.close(fd)
if __name__ == "__main__":
# 真实项目可在这里接入参数解析;示例只保留函数调用入口。
try:
copied = splice_copy("source.bin", "target.bin")
print(f"传输完成:{copied} 字节")
except AttributeError as exc:
# 当前 Python 或平台没有暴露 os.splice 时给出明确原因。
raise RuntimeError("当前环境不提供 os.splice") from exc
except OSError as exc:
# 权限、文件系统和内核约束都通过 OSError 暴露。
raise RuntimeError(f"splice 传输失败:{exc}") from exc
这里用了两层循环。外层负责不断从源文件取块,内层负责把本次进入管道的字节全部排到目标文件。不能假设一次 os.splice 一定返回请求的 count,否则在管道容量、非阻塞模式或底层 I/O 状态变化时可能留下未写完的数据。
处理偏移量、短传输和 EOF
对普通文件来说,offset_src=None 或 offset_dst=None 表示使用文件当前位置;传入整数则表示从指定偏移读或写。管道没有可供随机定位的文件位置,所以对应的 offset 必须是 None。如果需要重复读取同一个源文件片段,应该重新定位普通文件描述符,不能给管道设置偏移。

| 现象 | 应如何判断 | 处理方式 |
|---|---|---|
返回值小于 count | 本次只完成了部分传输 | 按返回值减少剩余字节,继续调用 |
返回值等于 0 | 输入端没有更多数据,或管道没有可传数据 | 文件复制通常结束;管道场景要结合写端是否仍存在判断 |
| 管道一端传了整数 offset | 参数违反管道定位约束 | 改为 None,只给普通文件使用显式偏移 |
| 同一块数据要排空 | 源到管道和管道到目标的返回值可能不同 | 用剩余字节循环,直到本块全部送出 |
代码中的 moved_to_pipe 只表示进入管道的字节数;它不等于已经写入目标文件的字节数。只有内层循环把 remaining 减到零,外层才可以开始下一块。这个区分是避免尾部数据丢失的关键。
选择 flags 并控制阻塞行为
flags 可以用按位或组合官方提供的标志,但不要把它们当成“开启零拷贝”的开关,数据路径本身已经由 os.splice 决定。
os.SPLICE_F_MOVE:请求内核尽量移动管道页,而不是复制页;内核无法移动时仍可能复制。os.SPLICE_F_NONBLOCK:请求管道操作非阻塞,但相关文件描述符本身仍可能使调用阻塞,不能只看这个 flag 判断整个调用一定立即返回。os.SPLICE_F_MORE:提示后续还会有数据,适合连续分块传输的场景,但它是提示,不是完成语义。
如果使用 SPLICE_F_NONBLOCK,还要为 BlockingIOError 设计重试或事件循环策略;单纯把 flag 加上而不处理暂时不可读、不可写,会把“稍后继续”误判为传输失败。
排查平台和文件系统限制
- 先确认运行平台。官方文档把
os.splice标为 Linux API,其他系统不能按相同代码假设可用。 - 再确认 Python 版本。该接口从 Python 3.10 加入,过低版本可能没有这个属性。
- 检查管道约束。源和目标都为普通文件时,必须加入管道中转;管道对应的 offset 只能为
None。 - 检查文件系统关系。官方文档说明相关文件不在同一文件系统时可能以
EXDEV失败,跨挂载点复制应准备普通读写或其他兼容路径。 - 保留真实的
OSError。权限、无效描述符、内核不支持和文件系统限制不应被统一改写成“复制失败”而丢掉 errno。
常见问题
os.splice 能不能直接把一个普通文件复制到另一个普通文件?
不能按普通文件到普通文件的方式直接假设可用。至少一端必须是管道,文件复制通常采用“源文件—管道—目标文件”的两次调用。
为什么一次 splice 返回的字节数比 count 小?
系统调用返回的是本次实际传输量,不承诺一次填满请求数量。管道容量和底层 I/O 状态都可能让它短传输,因此要按返回值继续循环。
什么时候 offset 必须写 None?
只要对应的描述符是管道,就不能使用显式偏移。普通文件可以用 None 表示当前位置,也可以使用整数偏移。
os.splice 和 Python 的 file.read、file.write 有什么区别?
read 与 write 会把数据带入 Python 用户态;os.splice 面向文件描述符和内核管道,目标是减少内核与用户态之间的额外搬运,但平台和文件系统约束也更严格。
总结:Python os.splice 的使用重点是先设计好“文件描述符—管道—文件描述符”的拓扑,再用循环处理短传输和 EOF。偏移量只给普通文件使用,管道一端保持 None,最后在 finally 中关闭所有描述符,才能把这个 Linux 专用低层接口用得稳定。
Python TaskGroup 怎样让子任务失败统一收敛
- 上一篇
- Python TaskGroup 怎样让子任务失败统一收敛
- 下一篇
- Python enum.FlagBoundary 怎样处理未知标志位
-
- 文章 · python教程 | 12分钟前 | Python enum flag 位运算 IntFlag FlagBoundary
- Python enum.FlagBoundary 怎样处理未知标志位
- 476浏览 收藏
-
- 文章 · python教程 | 28分钟前 |
- Python TaskGroup 怎样让子任务失败统一收敛
- 501浏览 收藏
-
- 文章 · python教程 | 18小时前 | CLI · python · Python optparse OptionGroup 命令行帮助
- Python optparse.OptionGroup 怎样把旧 CLI 帮助选项分组
- 116浏览 收藏
-
- 文章 · python教程 | 18小时前 | 配置文件 · Python 命令行参数 argparse fromfile_prefix_chars 参数文件
- Python argparse.fromfile_prefix_chars 怎么从参数文件读取长命令
- 151浏览 收藏
-
- 文章 · python教程 | 18小时前 |
- Python Base85 和 Base64 有什么区别,短文本该怎么选
- 365浏览 收藏
-
- 文章 · python教程 | 18小时前 |
- Python bz2.BZ2Decompressor 怎么按输入需求循环解压数据流
- 250浏览 收藏
-
- 文章 · python教程 | 18小时前 | 类型转换 · pyarrow 安全转换 整数溢出 compute.cast CastOptions Arrow类型
- PyArrow compute.cast 溢出时怎么选择安全转换策略
- 139浏览 收藏
-
- 文章 · python教程 | 18小时前 |
- PyArrow write_dataset 怎么限制每个 Parquet 文件的行数
- 444浏览 收藏
-
- 文章 · python教程 | 18小时前 | python · Python pyarrow table ChunkedArray combine_chunks
- PyArrow Table 怎么合并多个 ChunkedArray 以便连续读取
- 200浏览 收藏
-
- 文章 · python教程 | 18小时前 | 事务 · python · sqlalchemy · 数据库迁移 · sqlalchemy TEXT Alembic bindParam 参数化SQL op.get_bind 迁移脚本
- Alembic op.get_bind 怎么在迁移脚本中执行参数化 SQL
- 371浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 986次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 991次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 1114次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 1083次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 929次使用
-
- Python TaskGroup 怎样让子任务失败统一收敛
- 2026-11-12 501浏览
-
- Python xml.dom.minidom.unlink 怎样释放不再使用的 DOM 树引用
- 2026-10-27 501浏览
-
- Python typing 怎样用 TypeIs 缩小类型
- 2026-10-24 501浏览
-
- Python sqlite3 Connection serialize 怎么导出数据库快照:备份窗口、内存占用与恢复校验
- 2026-08-26 501浏览
-
- Python监控网页状态:requests异常处理实战
- 2026-05-29 501浏览

