如何复制文件

3747

如何在Python中复制文件?


3
如果您指定复制的原因,那就太好了。对于许多应用程序而言,硬链接可能是一个可行的替代方案。而且寻找这种解决方案的人也可以考虑这个“复制”机会(就像我一样,但我的答案在这里被投了反对票)。 - Yaroslav Nikitenko
27个回答

1

我想提出一个不同的解决方案。

def copy(source, destination):
   with open(source, 'rb') as file:
       myFile = file.read()
   with open(destination, 'wb') as file:
       file.write(myFile)

copy("foo.txt", "bar.txt")

文件已经打开,它的数据将被写入到您选择的新文件中。

在Linux中,这对符号链接或硬链接是不安全的,链接的文件会被多次重写。 - Tcll

0

对于大家推荐的答案,如果您不想使用标准模块,或者像我一样完全删除了它们,更喜欢使用核心C方法而不是编写不良Python方法

shutil的工作方式是符号链接/硬链接安全的,但由于os.path.normpath()包含一个while(nt,mac)或for(posix)循环,用于测试shutil.copyfile()中的srcdst是否相同,因此速度较慢。

如果您确定srcdst永远不会是同一个文件,则此部分大多数情况下是不需要的,否则可能可以使用更快的C方法。
(请注意,仅因为一个模块可能是C并不意味着它本质上更快,在使用之前请确保您使用的是编写良好的模块)

在进行初始测试之后,copyfile()在动态元组(src,dst)上运行for循环,测试特殊文件(例如posix中的套接字或设备)。

最后,如果follow_symlinks为False,则copyfile()会使用os.path.islink()测试src是否为符号链接,在Windows和Linux上可能是nt.lstat()posix.lstat()os.lstat()),在Mac上可能是Carbon.File.ResolveAliasFile(s, 0)[2]
如果该测试返回True,则复制符号链接/硬链接的核心代码如下:

        os.symlink(os.readlink(src), dst)

在posix中,硬链接是通过posix.link()完成的,尽管可以通过os.link()调用,但shutil.copyfile()并不会调用它。
(可能是因为检查硬链接的唯一方法是对我们知道的第一个inode的os.lstat()(特别是st_inost_dev)进行哈希映射,并假定那是硬链接目标)

否则,文件复制是通过基本文件缓冲区完成的:

       with open(src, 'rb') as fsrc:
           with open(dst, 'wb') as fdst:
               copyfileobj(fsrc, fdst)

(与其他答案类似)

copyfileobj() 有点特殊,因为它是缓冲区安全的,使用 length 参数以块的形式读取文件缓冲区:

def copyfileobj(fsrc, fdst, length=16*1024):
    """copy data from file-like object fsrc to file-like object fdst"""
    while 1:
        buf = fsrc.read(length)
        if not buf:
            break
        fdst.write(buf)

希望这个答案能够为使用Python核心机制进行文件复制的神秘面纱提供一些启示。 :)
总体而言,shutil写得还不错,特别是在copyfile()的第二个测试之后,因此如果你懒得去做,它并不是一个可怕的选择,但由于轻微膨胀,初始测试将会有点慢,所以在大规模复制时可能会有些缺陷。

-1

您可以使用system

对于类Unix系统:

import os

copy_file = lambda src_file, dest: os.system(f"cp {src_file} {dest}")

copy_file("./file", "../new_dir/file")

-2

这里是一个使用"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)

-2

您可以使用 os.link 创建文件的硬链接:

os.link(source, dest)

这不是一个独立的克隆,但如果您计划仅读取(不修改)新文件并且其内容必须与原始文件保持相同,则这将非常有效。它还有一个好处,即如果您想检查副本是否已经存在,则可以比较硬链接(使用os.stat),而不是它们的内容。

在Linux中,命令cp带有键

cp -al

创建硬链接。因此,硬链接可以被视为副本。有时候,一个人需要的正是这种行为(从不同位置访问文件内容),而不需要单独的副本。


-2
Python 提供了内置函数,可以使用操作系统的 shell 工具轻松地复制文件。
以下命令用于复制文件:
shutil.copy(src, dst)

以下命令用于复制带有元数据信息的文件:

shutil.copystat(src, dst)

你应该先运行 copy 然后再运行 copystat 以保留文件元数据。在 Python 3.3+ 中,copystat 还会复制扩展属性。 - ingyhere

-7

shutil.copy(src, dst, *, follow_symlinks=True)

shutil.copy(源路径,目标路径,*,follow_symlinks=True)


1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community
8
其他回答中已经提到过这一点。当回答那些已经有答案的老问题时,请确保您提供的是一种新的解决方案或者比现有答案更好的解释。 - Eric Aya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接