如何在Python中复制文件?


当前回答

这是一个利用“shutil.copyfileobj”的答案,它非常高效。我在不久前创建的一个工具中使用了它。我最初没有写这篇文章,但我稍微修改了一下。

def copyFile(src, dst, buffer_size=10485760, perserveFileDate=True):
    '''
    @param src:    Source File
    @param dst:    Destination File (not file path)
    @param buffer_size:    Buffer size to use during copy
    @param perserveFileDate:    Preserve the original file date
    '''
    #    Check to make sure destination directory exists. If it doesn't create the directory
    dstParent, dstFileName = os.path.split(dst)
    if(not(os.path.exists(dstParent))):
        os.makedirs(dstParent)

    # Optimize the buffer for small files
    buffer_size = min(buffer_size,os.path.getsize(src))
    if(buffer_size == 0):
        buffer_size = 1024

    if shutil._samefile(src, dst):
        raise shutil.Error("`%s` and `%s` are the same file" % (src, dst))
    for fn in [src, dst]:
        try:
            st = os.stat(fn)
        except OSError:
            # File most likely does not exist
            pass
        else:
            # XXX What about other special files? (sockets, devices...)
            if shutil.stat.S_ISFIFO(st.st_mode):
                raise shutil.SpecialFileError("`%s` is a named pipe" % fn)
    with open(src, 'rb') as fsrc:
        with open(dst, 'wb') as fdst:
            shutil.copyfileobj(fsrc, fdst, buffer_size)

    if(perserveFileDate):
        shutil.copystat(src, dst)

其他回答

Function Copies
metadata
Copies
permissions
Uses file object Destination
may be directory
shutil.copy No Yes No Yes
shutil.copyfile No No No No
shutil.copy2 Yes Yes No Yes
shutil.copyfileobj No No Yes No

目录和文件复制示例,来自Tim Golden的Python Stuff:

import os
import shutil
import tempfile

filename1 = tempfile.mktemp (".txt")
open (filename1, "w").close ()
filename2 = filename1 + ".copy"
print filename1, "=>", filename2

shutil.copy (filename1, filename2)

if os.path.isfile (filename2): print "Success"

dirname1 = tempfile.mktemp (".dir")
os.mkdir (dirname1)
dirname2 = dirname1 + ".copy"
print dirname1, "=>", dirname2

shutil.copytree (dirname1, dirname2)

if os.path.isdir (dirname2): print "Success"

与公认的答案类似,如果您还想确保在目标路径中创建任何(不存在的)文件夹,以下代码块可能会很有用。

from os import path, makedirs
from shutil import copyfile
makedirs(path.dirname(path.abspath(destination_path)), exist_ok=True)
copyfile(source_path, destination_path)

正如公认的答案所指出的,这些行将覆盖目标路径上存在的任何文件,因此有时在该代码块之前添加:if not path.exists(destination_path):可能会很有用。

这里有一个简单的方法,不需要任何模块。这与这个答案类似,但如果它是一个不适合RAM的大文件,那么它也可以工作:

with open('sourcefile', 'rb') as f, open('destfile', 'wb') as g:
    while True:
        block = f.read(16*1024*1024)  # work by blocks of 16 MB
        if not block:  # end of file
            break
        g.write(block)

因为我们正在编写一个新文件,所以它不会保留修改时间等。如果需要,我们可以使用os.utime。

您可以使用shutil软件包中的复制功能之一:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Function              preserves     supports          accepts     copies other
                      permissions   directory dest.   file obj    metadata  
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
shutil.copy              ✔             ✔                 ☐           ☐
shutil.copy2             ✔             ✔                 ☐           ✔
shutil.copyfile          ☐             ☐                 ☐           ☐
shutil.copyfileobj       ☐             ☐                 ✔           ☐
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

例子:

import shutil
shutil.copy('/etc/hostname', '/var/tmp/testhostname')