You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中快速迁移Ubuntu下跨驱动器的数百GB大文件并显示进度

1. 和shutil.move的速度差异

分两种场景对比:

  • 同文件系统内移动:shutil.move直接修改文件系统元数据,不需要拷贝数据,瞬间完成,速度远快于你自己实现的读写拷贝方案,差异极大。
  • 跨驱动器移动:shutil.move底层会调用shutil.copyfile完成数据拷贝,再删除原文件,和你的实现逻辑本质一致。但你当前代码里chunk_size=4096的设置太小,会导致循环开销远高于shutil.copyfile(其默认块大小为1MB),实际运行速度会比shutil.move慢30%以上,差异非常明显。如果将块大小调整到1MB~32MB区间后,加上tqdm的开销可以忽略,速度和shutil.move基本持平。

2. 更高效的实现方案

核心优化方向围绕减少拷贝开销、降低循环次数:

  • 调整块大小:磁盘IO的最小单位通常是4KB,但连续读写时用更大的块可以大幅减少用户态循环开销,推荐设置为`16 * 1024 * 1024(16MB),内存占用极低,速度提升明显。
  • 使用Linux零拷贝系统调用os.sendfile:普通的read/write需要将数据从内核缓冲区拷贝到用户态再拷回内核缓冲区,sendfile直接在内核态完成数据拷贝,不需要经过用户态,CPU占用降低50%以上,速度也会有10%~20%的提升,示例代码如下:
import os
from pathlib import Path
from tqdm import tqdm

large_file = Path('/path/to/large_file')
new_loc = Path('/new/path/large_file')
chunk_size = 16 * 1024 * 1024  # 16MB 块大小
file_size = large_file.stat().st_size

with open(large_file, 'rb') as f_in, open(new_loc, 'wb') as f_out:
    with tqdm(total=file_size, unit='B', unit_scale=True, desc="传输进度") as pbar:
        offset = 0
        while offset < file_size:
            sent = os.sendfile(f_out.fileno(), f_in.fileno(), offset, chunk_size)
            if sent == 0:
                raise RuntimeError("文件读取提前结束")
            offset += sent
            pbar.update(sent)

# 校验文件完整性后再删除原文件
if new_loc.stat().st_size == file_size:
    # 可选:补充哈希校验,避免数据传输损坏
    large_file.unlink()
else:
    new_loc.unlink()
    raise RuntimeError("文件传输不完整,已删除损坏的目标文件")
  • 增加完整性校验:数百GB的文件传输过程中存在数据损坏的风险不低,建议传输完成后可以对比文件哈希值再删除原文件,避免数据丢失。

3. 是否需要用C扩展或ctypes

完全没有必要。跨驱动器大文件传输的瓶颈完全在磁盘IO速度上,Python层的逻辑开销占总耗时的比例不到1%,就算用纯C实现相同逻辑,最终速度也受限于磁盘的连续读写速度,不会有可感知的提升。当前场景下使用os.sendfile已经直接调用了系统底层的最优接口,不需要额外做底层优化。

内容的提问来源于stack exchange,提问作者Andres

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 20:54:04