当前位置:首页 > 文章列表 > 文章 > python教程 > Python os.splice 怎样在文件描述符之间传输数据

Python os.splice 怎样在文件描述符之间传输数据

来源:17golang原创 2026-11-12 01:59:04 0浏览 收藏

如果目标是在 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 os.splice 通过内核管道在源文件描述符和目标文件描述符之间传输数据的结构说明图
图1:os.splice 通过内核管道连接源文件和目标文件的结构图;用于理解关系,不代表运行截图。

因此,常见的文件复制拓扑是“源文件 → 管道写端 → 管道读端 → 目标文件”。中间的管道不是为了让 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。如果需要重复读取同一个源文件片段,应该重新定位普通文件描述符,不能给管道设置偏移。

Python os.splice 的源偏移、目标偏移、管道 offset 限制和 EOF 返回值说明图
图2:os.splice 偏移量、管道约束和返回值语义说明图;用于理解关系,不代表运行截图。
现象应如何判断处理方式
返回值小于 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 加上而不处理暂时不可读、不可写,会把“稍后继续”误判为传输失败。

排查平台和文件系统限制

  1. 先确认运行平台。官方文档把 os.splice 标为 Linux API,其他系统不能按相同代码假设可用。
  2. 再确认 Python 版本。该接口从 Python 3.10 加入,过低版本可能没有这个属性。
  3. 检查管道约束。源和目标都为普通文件时,必须加入管道中转;管道对应的 offset 只能为 None。
  4. 检查文件系统关系。官方文档说明相关文件不在同一文件系统时可能以 EXDEV 失败,跨挂载点复制应准备普通读写或其他兼容路径。
  5. 保留真实的 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 专用低层接口用得稳定。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Python TaskGroup 怎样让子任务失败统一收敛Python TaskGroup 怎样让子任务失败统一收敛
上一篇
Python TaskGroup 怎样让子任务失败统一收敛
Python enum.FlagBoundary 怎样处理未知标志位
下一篇
Python enum.FlagBoundary 怎样处理未知标志位
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    986次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    991次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    1114次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    1083次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    929次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码