Python 拷贝大文件时如何选择合适的分片大小?

python 拷贝大文件一般套路是:

with open(src_file, "rb") as fr, open(dst_file, 'wb') as fw:  # fr 读文件
    while True:
        data = fr.read(4096)
        if not data:
            break
        fw.write(data)

后面跟一些异常处理,4096 这个是 4 KB,这个大小受什么因素影响?

写 1 * 1024 * 1024 行吗?我感觉性能完全够啊


Python 拷贝大文件时如何选择合适的分片大小?

17 回复

1MB 当然可以。4KB 很可能就是随便写的一个数。

但是一般不会用 Python 去追求性能。高性能复制大文件还是直接走系统工具比较好吧。


在Python里拷贝大文件,用分片(chunk)来读写是标准做法,能有效控制内存。分片大小的选择没有绝对标准,得看你的场景。

核心原则:在内存占用、系统调用开销和磁盘I/O效率之间找平衡。

  1. 默认值(通常够用):很多库(如shutil.copyfileobj)默认用16KB或64KB。这是一个安全的起点,适用于绝大多数情况。
  2. 内存考虑:分片越大,单次占用内存越多。如果你在内存受限的环境(如嵌入式设备、低配VPS),建议用较小的值,如4KB、16KB或64KB。
  3. 性能调优(高级场景)
    • 对于机械硬盘(HDD),较大的分片(如128KB、256KB甚至1MB)可以减少磁头寻道次数,可能提升连续读写速度。
    • 对于固态硬盘(SSD) 和现代操作系统,较小的分片(如64KB)通常也能跑满带宽,分片大小的影响变小。
    • 网络文件系统或远程拷贝时,可能需要匹配网络包大小或协议块大小。

给你一个实用的代码示例和测试思路

import shutil
import time

def copy_file_chunked(src, dst, buffer_size=64*1024):
    """使用指定分片大小拷贝文件"""
    with open(src, 'rb') as fsrc:
        with open(dst, 'wb') as fdst:
            shutil.copyfileobj(fsrc, fdst, buffer_size)

# 测试不同分片大小的耗时
src_file = 'large_file.iso'  # 你的大文件
dst_template = 'copy_test_{}.iso'

chunk_sizes = [4*1024, 16*1024, 64*1024, 256*1024, 1024*1024]  # 4KB, 16KB, 64KB, 256KB, 1MB

for size in chunk_sizes:
    dst_file = dst_template.format(size)
    start = time.time()
    copy_file_chunked(src_file, dst_file, buffer_size=size)
    elapsed = time.time() - start
    print(f"Buffer {size//1024}KB: {elapsed:.2f} seconds")

直接建议从64KB开始,如果遇到性能瓶颈,再用上面的方法实测调整。

简单说,别想太复杂,64KB是个靠谱的起点。

为啥不用标准库 shutil,搞这种没人用的所谓套路

自己对比测试一下不就知道了

我再看看。
即使是 shutil 也有缓存大小参数的,这不跟这问题一样吗
我自己测试打印时间倒是不难,但是害怕系统调度之类的其他因素会影响到结果

怕受随机因素影响就多做几次嘛

文件系统 block size 一般是 4k 吧




4KB 不是随机的一个数,Block device 的读操作是按照 block size 来的,读操作按照 block size align 才会更快( size 是 block size 的倍数)。

我写了一坨,但是后面的内容不知道为啥就是在 V2EX 发不出来,链接也发不出来…

我贴下 gist 链接转成的 base64 吧,查看方式:

echo aHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vbGFpeGludGFvLzE0MTJmYTAwOTg5M2VkNDYwMGNmMTE0OGVkMDRhOWIxCg== | base64 -D

希望你能解答你的疑惑。

和 block size 没有关系,你读的文件早就中间有文件系统层

应用程序 — 文件系统层 — 块设备层 — scsi/nvme/mtd… — 硬件

如果你的程序是直接读写块设备而不是文件系统(常见的有镜像烧写软件),再考虑 block size 的问题。

直接读写文件时,文件系统会处理好这些低级细节并执行缓冲和缓存。

为什么这个值要大:

因为 IO 操作(不仅 IO 操作,是全部的系统调用)是很消耗 CPU 的(涉及特权级别切换等耗时操作,特别是 Intel 漏洞使这方面更加剧了)。对于一个文件而言,缓冲区越大意味着调用系统调用的次数越少。

不过 block size 不一定是 4K 吧。

4k 是 Linux 的 page size 啊,这是文件缓存层层读文件的最小单位,即使应用层只读一个字节真实也会加载一个页缓存下来。少于一个 page 读多次会浪费 cpu 时间。详询 File Page Cache

嗯,不一定。 不过一般是 4k,我那个链接后面有说可以用 stat 看 block size,只要是 block size 的倍数就可以

正确的拷贝大文件的正确套路是。。。。。有系统 API 就直接用系统 API,cpython/blob/master/Lib/shutil.py#L227

发个 github 链接需要验证手机号码?这是啥套路?

感谢回复。
如果不是需要知道每一行内容的话,rb 速率比 r 高,而且安全一些,
因为 r 遇到一些特殊字符还有可能提前退出。
另外这边讨论的是拷贝不是读取[捂脸]

回到顶部