Python中os.copy_file_range搭配O_APPEND报错:Bad file descriptor问题
问题原因
os.copy_file_range 底层调用的是Linux内核的copy_file_range()系统调用,该调用不允许目标文件描述符以O_APPEND模式打开。
原因在于:O_APPEND模式会强制内核将所有写入操作的偏移量自动设置为文件末尾,但copy_file_range是基于显式偏移量实现高效块级复制的,当目标fd带有O_APPEND标记时,内核会判定该fd不符合操作要求,返回EBADF(错误号9,对应"Bad file descriptor")。
你提到os.write在O_APPEND模式下能正常工作,是因为write()系统调用本身兼容O_APPEND模式——内核会自动调整偏移量后执行写入,但copy_file_range的设计逻辑不支持这种自动调整。
高效解决办法
要保持copy_file_range的高效性同时实现追加复制,可通过手动指定目标文件的偏移量替代O_APPEND模式,具体步骤如下:
- 获取目标文件的当前大小(作为追加的起始偏移量)
- 以普通只写模式打开目标文件(无需
O_APPEND) - 调用
copy_file_range时显式传入目标偏移量参数
示例代码:
import os from_path = "source.txt" to_path = "target.txt" # 获取目标文件当前大小,作为追加起始位置 try: target_offset = os.path.getsize(to_path) except FileNotFoundError: target_offset = 0 fd_from = os.open(from_path, os.O_RDONLY) # 用O_WRONLY | O_CREAT确保文件存在(若需保留原有权限,可添加mode参数,比如0o644) fd_to = os.open(to_path, os.O_WRONLY | os.O_CREAT) # 显式指定目标偏移量,实现追加效果 os.copy_file_range(fd_from, fd_to, os.path.getsize(from_path), dst_offset=target_offset) os.close(fd_from) os.close(fd_to)
这个方法完全复用copy_file_range的高效块复制能力,效率和你之前正常运行的版本一致,同时满足追加到目标文件末尾的需求。
补充说明
你提到此前类似代码可正常运行,大概率是因为当时目标文件并未以O_APPEND模式打开,或者使用了更低版本的内核(部分旧内核对copy_file_range的参数限制更宽松,但5.15版本的内核已明确禁止O_APPEND的目标fd)。
内容的提问来源于stack exchange,提问作者Calhau18
相关产品推荐
相关产品推荐

