如何复制文件

3747

如何在Python中复制文件?


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

22

shutil 模块提供了一些高级文件操作功能,支持文件 复制移除

根据您的使用情况,请参考以下表格。

功能 使用
文件对象
保留文件
元数据
保留
权限
支持
目录目标
shutil.copyfileobj
shutil.copyfile
shutil.copy2
shutil.copy

6
你为什么复制了 jezrael 7年前的回答 - bfontaine

21

Python 3.5开始,您可以对小文件(即文本文件、小型JPEG图像)执行以下操作:

from pathlib import Path

source = Path('../path/to/my/file.txt')
destination = Path('../path/where/i/want/to/store/it.txt')
destination.write_bytes(source.read_bytes())

write_bytes 会覆盖目标位置上的任何内容。


为什么只能处理小文件? - Kevin
@Kevin,我的错误,我应该在事情刚发生时就记录下原因。现在我需要重新审查并更新这个问题,因为我已经记不清了 ¯_(ツ)_/¯ - Marc
1
@Kevin 因为这会将所有内容加载到内存中。 - bfontaine

20

你可以使用 os.system('cp 由程序生成的文件名 /其他目录/')

或者像我这样做:

os.system('cp '+ rawfile + ' rawdata.dat')

这里的 rawfile 是在程序中我所生成的名称。

这是仅适用于Linux系统的解决方案。


17
这并不是可移植的,而且也没必要,因为你可以直接使用shutil。 - Corey Goldberg
6
即使没有shutilsubprocess.run()(不使用shell=True!)也是比os.system()更好的选择。 - maxschlepzig
2
shutil更具可移植性。 - Hiadore
2
subprocess.run() 正如 @maxschlepzig 建议的那样,在调用外部程序时是一个很大的进步。然而,为了灵活性和安全性,请使用 ['cp', rawfile, 'rawdata.dat'] 形式来传递命令行。 (但是,对于复制操作,建议使用 shutil 和相关工具,而不是调用外部程序。) - Marcel Waldvogel
2
尝试使用带空格的文件名。 - Jean-François Fabre

20

在Python中有两种最佳的文件复制方法。

1. 我们可以使用shutil模块

代码示例:

import shutil
shutil.copyfile('/path/to/file', '/path/to/new/file')

除了copyfile之外,还有其他可用的方法,比如copy、copy2等等,但从性能角度来看,copyfile是最好的。

2. 我们可以使用OS模块

代码示例:

import os
os.system('cp /path/to/file /path/to/new/file')

另一种方法是通过使用子进程,但这并不是首选方法,因为它是其中一种调用方法,并且不安全。

它应该链接到文档(但不是裸链接)。 - Peter Mortensen
1
为什么我们需要一个新的答案? - Peter Mortensen
@PeterMortensen,已添加链接。该答案会增加价值,因为其他答案要么太宽泛,要么太直接了当,而这个答案包含了可以轻松使用的有用信息。 - Ritik Banger
1
我觉得你可能有些困惑。Python的os.system文档中指出:“subprocess模块提供了更强大的功能,用于生成新的进程并获取其结果;使用该模块比使用此函数更可取。”你提到subprocess可能存在安全问题。然而,只有在shell=True的情况下才会存在这些问题(shell=False是默认设置),而且使用os.system时也存在相同的安全问题(未经过处理的用户输入)。与你的os.system示例相比,以下代码更可取:subprocess.run(['cp', dst, src])。 - undefined

14

使用

open(destination, 'wb').write(open(source, 'rb').read())

以读模式打开源文件,以写模式写入目标文件。


2
所有答案都需要解释,即使只有一句话。不解释会树立不好的先例,也没有助于理解程序。如果一个完全不懂Python的新手看到这个答案,想使用它,但因为不理解而无法使用怎么办?你应该对所有人都有帮助的回答。 - miike3459
3
所有的open(...)都没有调用.close(),不是吗? - luckydonald
不需要使用 .close(),因为我们在任何地方都没有存储文件指针对象(无论是源文件还是目标文件)。 - Sun
据我所知,当文件实际关闭时是未定义的,@SundeepBorra。建议使用with(如上面的示例)而不是更复杂的方法。在原始文件上使用read()会将整个文件读入内存,这可能太大了。使用像shutil中的标准函数,这样您和其他参与代码的人就不需要担心特殊情况。https://docs.python.org/3/library/io.html#io.BufferedReader - Marcel Waldvogel
2
yellow01的答案相同,采用了低效的浪费内存的方法。 - maxschlepzig

13

对于大文件,我逐行读取文件并将每一行读入数组中。然后,一旦数组达到一定大小,就将其附加到新文件中。

for line in open("file.txt", "r"):
    list.append(line)
    if len(list) == 1000000: 
        output.writelines(list)
        del list[:]

2
这似乎有点冗余,因为编写者应该处理缓冲。for l in open('file.txt','r'): output.write(l) 应该可以工作;只需根据您的需要设置输出流缓冲区即可。或者您可以通过循环尝试来按字节进行操作 output.write(read(n)); output.flush(),其中 n 是您想要一次写入的字节数。这两种方法都没有检查条件,这是一个优点。 - owns
1
是的,但我认为这可能更容易理解,因为它复制整行而不是它们的部分(以防我们不知道每行有多少字节)。 - rassa45
@owns 一年后再补充这个问题,writelines() 相对于 write() 显示出稍微更好的性能,因为我们不会浪费时间不断打开新的文件流,而是将新行作为一个大的字节流写入。 - rassa45
1
查看源代码 - writelines 调用 write,https://hg.python.org/cpython/file/c6880edaf6f3/Modules/_io/bytesio.c。此外,文件流已经打开,因此每次写入时不需要重新打开它。 - owns
3
这太糟糕了。它做了许多无谓的工作,却没有好处。它不能用于任意文件。如果输入在类似Windows的系统上有不寻常的换行符,则复制结果不是完全一致的字节。你为什么认为这比在“shutil”中调用复制函数更容易理解呢?即使忽略“shutil”,一个简单的块读写循环(使用未缓冲的IO)也是直截了当的、高效的,比这要合理得多,因此肯定更容易教授和理解。 - maxschlepzig
这也增加了解码/编码开销,并且不能用于二进制数据。**只需使用shutil.copyfile()**,在3.8上已经进一步改进以使用本机操作系统支持的快速文件复制。它很容易比这个答案所需的时间少一半。 - Martijn Pieters

13

使用 subprocess.call 来复制文件

from subprocess import call
call("cp -p <file> <file>", shell=True)

22
这取决于平台,因此我不会使用它。 - Kevin Meier
10
这样的“调用”是不安全的。请参考子进程文档。 - buhtz
6
这不是可移植的,而且也没必要,因为你可以使用shutil。 - Corey Goldberg
5
为什么选择Python呢? - Baris Demiray
在开始之前,也许需要检测操作系统(无论是DOS还是Unix,因为它们是最常用的两种)。 - MilkyWay90

9

如果您已经看到了这里,答案是您需要完整的路径和文件名。

import os

shutil.copy(os.path.join(old_dir, file), os.path.join(new_dir, file))

如果展示了导入 os,你也应该导入 shutil。 - Ivelin

8

以下是一种简单的方法,不需要任何模块。它类似于这个答案,但它还有一个好处,即可用于大文件,这些文件无法适应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


4
与接受的答案类似,以下代码块可能也很有用,如果您还想确保在目标路径中创建所有(不存在的)文件夹。
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):也可能很有用。


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