如何快速复制文件 [重复]

Posted

技术标签:

【中文标题】如何快速复制文件 [重复]【英文标题】:How to Copy Files Fast [duplicate] 【发布时间】:2014-03-31 11:29:35 【问题描述】:

与使用 Windows 文件资源管理器或 Mac 的 Finder 进行常规右键单击复制 > 右键单击​​粘贴相比,使用 shutil.copyfile() 复制文件所需的时间至少长 3 倍。 在 Python 中有没有比shutil.copyfile() 更快的替代方法?可以做些什么来加快文件复制过程? (文件目标在网络驱动器上……如果有什么不同的话……)。

稍后编辑:

这是我最终得到的结果:

def copyWithSubprocess(cmd):        
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

win=mac=False
if sys.platform.startswith("darwin"):mac=True
elif sys.platform.startswith("win"):win=True

cmd=None
if mac: cmd=['cp', source, dest]
elif win: cmd=['xcopy', source, dest, '/K/O/X']

if cmd: copyWithSubprocess(cmd)

【问题讨论】:

您可以使用本机命令行选项,例如用于 Linux 和 Mac 的 cp 和用于 Windows 的 COPY。它们应该和使用 GUI 时一样快。 在 Windows 上 SHFileOperation 为您提供本机 shell 文件副本 根据问题中未说明的某些因素,在传输之前将文件打包到压缩存档中可能会有所帮助...您是否考虑过使用类似 rsync 的东西? 如果您担心所有权和 ACL,请不要仅出于这个原因使用 shutil:'On Windows, file owners, ACLs and alternate data streams are not copied.' 值得注意的是,在 Python 3.8 中,复制文件和目录的函数have been optimized 可以在几个主要操作系统上运行得更快。 【参考方案1】:

这只是一个猜测,但是...... 你的时间错了 ...也就是说,当你复制文件时,它会打开文件并将其全部读入内存,这样当你粘贴时你只创建一个文件并转储你的内存内容

在python中

copied_file = open("some_file").read()

相当于 ctrl + c 复制

然后

with open("new_file","wb") as f:
     f.write(copied_file)

ctrl + v 粘贴的等价物(所以时间是等价的......)

如果您希望它更适合更大的数据(但它不会像 ctrl+v /ctrl+c 那样快

with open(infile,"rb") as fin,open(outfile,"wb") as fout:
     fout.writelines(iter(fin.readline,''))

【讨论】:

我相信你会是一个很好的导师,很好! 好点。我应该更具体。而不是右键单击复制然后粘贴: 此架构: 1. 选择文件; 2. 拖动文件。 3 将文件拖放到目标文件夹中。 那是一个动作......这是非常不同的......尝试shutil.move而不是 此解决方案无法扩展。随着文件变大,这将成为一个不太可用的解决方案。您需要对操作系统进行多次系统调用,以便在文件变大时仍将部分文件读入内存。 我很难相信,如果你在 Windows 中按 CTRL + C 一个 100 GB 的文件,它会立即尝试将其加载到内存中......【参考方案2】:

对于 Windows,您可以简单地使用您正在执行复制的操作系统:

from subprocess import call
call(["xcopy", "c:\\file.txt", "n:\\folder\\", "/K/O/X"])

/K - 复制属性。通常,Xcopy 会重置只读属性 /O - 复制文件所有权和 ACL 信息。 /X - 复制文件审核设置(隐含 /O)。

【讨论】:

Windows 上的“xcopy”能否与“常规”子进程一起工作,例如:cmd = ['xcopy', source, dest, "/K/O/X"] subprocess.Popen(cmd , stdout=subprocess.PIPE, stderr=subprocess.PIPE) 这样也行。 太棒了!感谢您的帮助! 参数个数无效错误 请注意 /O 和 /X 标志需要提升的子进程,否则您将导致“访问被拒绝”【参考方案3】:
import sys
import subprocess

def copyWithSubprocess(cmd):        
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

cmd=None
if sys.platform.startswith("darwin"): cmd=['cp', source, dest]
elif sys.platform.startswith("win"): cmd=['xcopy', source, dest, '/K/O/X']

if cmd: copyWithSubprocess(cmd)

【讨论】:

经济解释,但这是一个很好的答案。【参考方案4】:

没有过度优化我使用以下代码获得的代码的最快版本:

class CTError(Exception):
    def __init__(self, errors):
        self.errors = errors

try:
    O_BINARY = os.O_BINARY
except:
    O_BINARY = 0
READ_FLAGS = os.O_RDONLY | O_BINARY
WRITE_FLAGS = os.O_WRONLY | os.O_CREAT | os.O_TRUNC | O_BINARY
BUFFER_SIZE = 128*1024

def copyfile(src, dst):
    try:
        fin = os.open(src, READ_FLAGS)
        stat = os.fstat(fin)
        fout = os.open(dst, WRITE_FLAGS, stat.st_mode)
        for x in iter(lambda: os.read(fin, BUFFER_SIZE), ""):
            os.write(fout, x)
    finally:
        try: os.close(fin)
        except: pass
        try: os.close(fout)
        except: pass

def copytree(src, dst, symlinks=False, ignore=[]):
    names = os.listdir(src)

    if not os.path.exists(dst):
        os.makedirs(dst)
    errors = []
    for name in names:
        if name in ignore:
            continue
        srcname = os.path.join(src, name)
        dstname = os.path.join(dst, name)
        try:
            if symlinks and os.path.islink(srcname):
                linkto = os.readlink(srcname)
                os.symlink(linkto, dstname)
            elif os.path.isdir(srcname):
                copytree(srcname, dstname, symlinks, ignore)
            else:
                copyfile(srcname, dstname)
            # XXX What about devices, sockets etc.?
        except (IOError, os.error), why:
            errors.append((srcname, dstname, str(why)))
        except CTError, err:
            errors.extend(err.errors)
    if errors:
        raise CTError(errors)

这段代码的运行速度比原生 linux "cp -rf" 慢一点。

与shutil相比,本地存储对tmfps的增益约为2-3倍,而NFS对本地存储的增益约为6倍。

在分析之后,我注意到 shutil.copy 做了很多 fstat syscals,这些都是相当重量级的。 如果想进一步优化,我建议为 src 做一个 fstat 并重用这些值。老实说,我并没有走得更远,因为我得到了与本地 linux 复制工具几乎相同的数字,并且优化数百毫秒不是我的目标。

【讨论】:

不确定这是否特定于更高版本的python(3.5+),但iter中的哨兵需要b''才能停止。 (至少在 OSX 上) 即使在修复 'except' 语法后也不能与 python 3.6 一起使用 这是一个python2版本。我还没有用 python3 测试过这个。可能python3原生文件树副本已经够快了,做个benchmark吧。 这比我尝试的任何其他方法都快。 仅供参考,我建议在写出文件后添加shutil.copystat(src, dst) 以提供元数据。

以上是关于如何快速复制文件 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何在mac电脑上快速复制文件或文件夹路径

怎样复制文件路径

如何快速将子文件夹下的文件全部复制到一个总的根目录下

如何让python将文件复制到桌面[重复]

快速文件复制与进度

如何快速复制文档目录中的远程服务器文件