如何复制文件

How to copy files

提问人:Matt 提问时间:9/24/2008 最后编辑:Peter MortensenMatt 更新时间:7/14/2023 访问量:3541791

问:

如何在 Python 中复制文件?

python 系统文件 复制

评论

3赞 Yaroslav Nikitenko 10/19/2022
如果您指定复制原因,那就太好了。对于许多应用程序,硬链接可能是一个可行的替代方案。寻找此类解决方案的人也可能会考虑这种“复制”机会(就像我一样,但我在这里的答案被否决了)。

答:

4607赞 Swati 9/24/2008 #1

Shutil 有很多方法可以使用。其中之一是:

import shutil

shutil.copyfile(src, dst)

# 2nd option
shutil.copy(src, dst)  # dst can be a folder; use shutil.copy2() to preserve timestamp
  • 将名为 的文件的内容复制到名为 的文件。两者都需要是文件的整个文件名,包括路径。srcdstsrcdst
  • 目标位置必须是可写的;否则,将引发异常。IOError
  • 如果已存在,则将其替换。dst
  • 特殊文件(如字符或块设备和管道)无法使用此功能复制。
  • 使用 和 是以 s 形式给出的路径名。copysrcdststr

另一种要查看的方法是 shutil.copy2()。它与此类似,但保留了更多元数据(例如时间戳)。shutil

如果使用操作,请使用 而不是 。 将只接受字符串。os.pathcopycopyfilecopyfile

评论

8赞 Martijn Pieters 3/20/2020
在 Python 3.8 中,这得到了一些显着的速度提升(~50%,具体取决于操作系统)。
2赞 KansaiRobot 11/7/2022
目标文件夹是否需要存在?
2赞 John 3/5/2023
@KansaiRobot:是的,否则你会得到一个例外:FileNotFoundError: Directory does not exist: foo/
0赞 Dimitri Lesnoff 10/4/2023
它不会像 POSIX 操作系统(GNU/Linux、FreeBSD 等)上的文件所有者组那样复制文件元数据。
86赞 Airsource Ltd 9/24/2008 #2

使用 shutil 模块

copyfile(src, dst)

将名为 src 的文件的内容复制到名为 dst 的文件中。目标位置必须是可写的;否则,将引发 IOError 异常。如果 dst 已存在,它将被替换。特殊文件(如字符或块设备和管道)无法使用此功能复制。srcdst 是以字符串形式给出的路径名。

查看 filesys 以了解标准 Python 模块中可用的所有文件和目录处理函数。

965赞 unmounted 9/24/2008 #3

copy2(src,dst) 通常比 copyfile(src,dst) 更有用,因为:

  • 它允许是一个目录(而不是完整的目标文件名),在这种情况下,basename 用于创建新文件;dstsrc
  • 它将原始修改和访问信息(mtime 和 atime)保留在文件元数据中(但是,这会产生轻微的开销)。

下面是一个简短的示例:

import shutil
shutil.copy2('/src/dir/file.ext', '/dst/dir/newname.ext') # complete target filename given
shutil.copy2('/src/file.ext', '/dst/dir') # target filename is /dst/dir/file.ext
108赞 pi. 9/24/2008 #4

复制文件是一个相对简单的操作,如下面的示例所示,但您应该改用 shutil stdlib 模块

def copyfileobj_example(source, dest, buffer_size=1024*1024):
    """      
    Copy a file from source to dest. source and dest
    must be file-like objects, i.e. any object with a read or
    write method, like for example StringIO.
    """
    while True:
        copy_buffer = source.read(buffer_size)
        if not copy_buffer:
            break
        dest.write(copy_buffer)

如果你想按文件名复制,你可以做这样的事情:

def copyfile_example(source, dest):
    # Beware, this example does not handle any edge cases!
    with open(source, 'rb') as src, open(dest, 'wb') as dst:
        copyfileobj_example(src, dst)
50赞 Noam Manos 3/15/2011 #5

目录和文件复制示例,来自 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"
20赞 mark 12/20/2014 #6

您可以使用 .os.system('cp nameoffilegeneratedbyprogram /otherdirectory/')

或者就像我所做的那样,

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

where 是我在程序中生成的名称。rawfile

这是仅限 Linux 的解决方案。

评论

17赞 Corey Goldberg 6/12/2017
这不是可移植的,而且没有必要,因为您可以只使用 shutil。
6赞 maxschlepzig 7/9/2017
即使不可用 - (没有!)是更好的选择。shutilsubprocess.run()shell=Trueos.system()
2赞 Hiadore 3/12/2019
Shutil 更便携
2赞 Marcel Waldvogel 4/29/2019
subprocess.run()正如@maxschlepzig所建议的那样,在调用外部程序时,这是向前迈出的一大步。但是,为了灵活性和安全性,请使用传递命令行的形式。(但是,对于复制,建议朋友不要调用外部程序。['cp', rawfile, 'rawdata.dat']shutil
2赞 Jean-François Fabre 4/30/2019
尝试使用带有空格的文件名。
2094赞 jezrael 5/21/2015 #7
功能 复制
元数据
复制
权限
使用文件对象 目标
可能是目录
shutil.copy 是的 是的
shutil.copy文件
shutil.copy2 是的 是的 是的
shutil.copyfileobj 是的
13赞 rassa45 5/25/2015 #8

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

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

评论

2赞 owns 6/13/2015
这似乎有点多余,因为编写器应该处理缓冲。 应该工作找到;只需根据需要设置输出流缓冲区即可。或者,您可以通过循环使用您一次要写入的字节数来按字节数进行。这两者也没有条件来检查哪个是奖金。for l in open('file.txt','r'): output.write(l)output.write(read(n)); output.flush()n
1赞 rassa45 6/14/2015
是的,但我认为这可能更容易理解,因为它复制了整行而不是部分行(以防我们不知道每行有多少字节)。
0赞 rassa45 11/30/2016
@owns 一年后,为了补充这个问题,它显示出更好的性能,因为我们不会浪费时间持续打开一个新文件流,而是将新行写成一个大字节。writelines()write()
1赞 owns 5/3/2017
查看源 - writelines 调用 write、hg.python.org/cpython/file/c6880edaf6f3/Modules/_io/bytesio.c。此外,文件流已经打开,因此写入不需要每次都重新打开它。
3赞 maxschlepzig 4/30/2019
这太可怕了。它无缘无故地做不必要的工作。它不适用于任意文件。如果输入在 Windows 等系统上具有不寻常的行尾,则副本的字节不相同。为什么你认为这可能比调用 中的复制函数更容易理解?即使忽略,一个简单的块读/写循环(使用无缓冲的 IO)也是直截了当的,会很有效,并且比这更有意义,因此肯定更容易教授和理解。shutilshutil
13赞 deepdive 4/4/2016 #9

用于复制文件subprocess.call

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

评论

22赞 Kevin Meier 9/13/2016
这取决于平台,所以我不会使用是。
10赞 buhtz 4/2/2017
这样是不安全的。请参考 subproces docu 关于它。call
6赞 Corey Goldberg 6/12/2017
这不是可移植的,而且没有必要,因为您可以只使用 shutil。
5赞 Baris Demiray 7/7/2017
嗯,为什么是 Python?
0赞 MilkyWay90 11/9/2018
也许在开始之前检测操作系统(无论是 DOS 还是 Unix,因为这是最常用的两个)
186赞 maxschlepzig 7/9/2017 #10

您可以使用 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')

评论

0赞 wim 3/23/2023
这比 2 年前的耶斯拉尔回答增加了什么?
0赞 maxschlepzig 3/23/2023
@wim你必须将我的答案与我发布我的答案时 jesrael 的答案进行比较。因此,我添加了另一列,使用了更好的列标题和较少分散注意力的表格布局。我还为最常见的情况添加了一个示例。你不是第一个问这个问题的人,我已经多次回答这个问题了,但不幸的是,一些版主删除了这里的旧评论。在检查了我的旧笔记后,你甚至似乎过去已经问过我这个问题,而你的问题和我的答案也被删除了。
0赞 maxschlepzig 3/23/2023
@wim我还在 Python 文档中添加了链接。添加的列包含有关目录目的地的信息,耶斯拉尔的回答不包括。
0赞 wim 3/23/2023
哦,亲爱的,我已经问过了,这很有趣。是的,我同意文档链接和额外列是改进,但是,将它们编辑成其他答案可能会更好。看起来一些用户随后这样做了,现在我们有两个答案,除了格式之外没有显着差异 - 建议删除?
43赞 fabda01 8/15/2017 #11

对于小文件和仅使用 Python 内置文件,可以使用以下单行代码:

with open(source, 'rb') as src, open(dest, 'wb') as dst: dst.write(src.read())

对于文件太大或内存至关重要的应用程序来说,这不是最佳方法,因此 Swati 的答案应该是首选。

评论

1赞 Tcll 4/24/2023
对符号链接或硬链接不安全,因为它会多次复制链接文件
33赞 Wizard 1/16/2018 #12

首先,我制作了一份详尽的 shutil 方法备忘单供您参考。

shutil_methods =
{'copy':['shutil.copyfileobj',
          'shutil.copyfile',
          'shutil.copymode',
          'shutil.copystat',
          'shutil.copy',
          'shutil.copy2',
          'shutil.copytree',],
 'move':['shutil.rmtree',
         'shutil.move',],
 'exception': ['exception shutil.SameFileError',
                 'exception shutil.Error'],
 'others':['shutil.disk_usage',
             'shutil.chown',
             'shutil.which',
             'shutil.ignore_patterns',]
}

其次,在示例中解释复制方法:

  1. shutil.copyfileobj(fsrc, fdst[, length])操作打开的对象

    In [3]: src = '~/Documents/Head+First+SQL.pdf'
    In [4]: dst = '~/desktop'
    In [5]: shutil.copyfileobj(src, dst)
    AttributeError: 'str' object has no attribute 'read'
    
    # Copy the file object
    In [7]: with open(src, 'rb') as f1,open(os.path.join(dst,'test.pdf'), 'wb') as f2:
        ...:      shutil.copyfileobj(f1, f2)
    In [8]: os.stat(os.path.join(dst,'test.pdf'))
    Out[8]: os.stat_result(st_mode=33188, st_ino=8598319475, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=13507926, st_atime=1516067347, st_mtime=1516067335, st_ctime=1516067345)
    
  2. shutil.copyfile(src, dst, *, follow_symlinks=True)复制和重命名

    In [9]: shutil.copyfile(src, dst)
    IsADirectoryError: [Errno 21] Is a directory: ~/desktop'
    # So dst should be a filename instead of a directory name
    
  3. shutil.copy()在不预先处理元数据的情况下进行复制

    In [10]: shutil.copy(src, dst)
    Out[10]: ~/desktop/Head+First+SQL.pdf'
    
    # Check their metadata
    In [25]: os.stat(src)
    Out[25]: os.stat_result(st_mode=33188, st_ino=597749, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=13507926, st_atime=1516066425, st_mtime=1493698739, st_ctime=1514871215)
    In [26]: os.stat(os.path.join(dst, 'Head+First+SQL.pdf'))
    Out[26]: os.stat_result(st_mode=33188, st_ino=8598313736, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=13507926, st_atime=1516066427, st_mtime=1516066425, st_ctime=1516066425)
    # st_atime,st_mtime,st_ctime changed
    
  4. shutil.copy2()复制并保留元数据

    In [30]: shutil.copy2(src, dst)
    Out[30]: ~/desktop/Head+First+SQL.pdf'
    In [31]: os.stat(src)
    Out[31]: os.stat_result(st_mode=33188, st_ino=597749, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=13507926, st_atime=1516067055, st_mtime=1493698739, st_ctime=1514871215)
    In [32]: os.stat(os.path.join(dst, 'Head+First+SQL.pdf'))
    Out[32]: os.stat_result(st_mode=33188, st_ino=8598313736, st_dev=16777220, st_nlink=1, st_uid=501, st_gid=20, st_size=13507926, st_atime=1516067063, st_mtime=1493698739, st_ctime=1516067055)
    # Preserved st_mtime
    
  5. shutil.copytree()

    以递归方式复制根植于 src 的整个目录树,返回目标目录。

271赞 kmario23 1/22/2018 #13

在 Python 中,您可以使用以下命令复制文件


import os
import shutil
import subprocess

1) 使用 shutil 模块复制文件

shutil.copyfile 签名

shutil.copyfile(src_file, dest_file, *, follow_symlinks=True)

# example    
shutil.copyfile('source.txt', 'destination.txt')

shutil.copy 签名

shutil.copy(src_file, dest_file, *, follow_symlinks=True)

# example
shutil.copy('source.txt', 'destination.txt')

shutil.copy2 签名

shutil.copy2(src_file, dest_file, *, follow_symlinks=True)

# example
shutil.copy2('source.txt', 'destination.txt')  

shutil.copyfileobj 签名

shutil.copyfileobj(src_file_object, dest_file_object[, length])

# example
file_src = 'source.txt'  
f_src = open(file_src, 'rb')

file_dest = 'destination.txt'  
f_dest = open(file_dest, 'wb')

shutil.copyfileobj(f_src, f_dest)  

2) 使用 os 模块复制文件

os.popen 签名

os.popen(cmd[, mode[, bufsize]])

# example
# In Unix/Linux
os.popen('cp source.txt destination.txt') 

# In Windows
os.popen('copy source.txt destination.txt')

os.system 签名

os.system(command)


# In Linux/Unix
os.system('cp source.txt destination.txt')  

# In Windows
os.system('copy source.txt destination.txt')

3) 使用子进程模块复制文件

subprocess.call 签名

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)

# example (WARNING: setting `shell=True` might be a security-risk)
# In Linux/Unix
status = subprocess.call('cp source.txt destination.txt', shell=True) 

# In Windows
status = subprocess.call('copy source.txt destination.txt', shell=True)

subprocess.check_output签名

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False)

# example (WARNING: setting `shell=True` might be a security-risk)
# In Linux/Unix
status = subprocess.check_output('cp source.txt destination.txt', shell=True)

# In Windows
status = subprocess.check_output('copy source.txt destination.txt', shell=True)

评论

3赞 Yaroslav Nikitenko 9/10/2022
感谢您列出的许多选项。恕我直言,“os.popen('cp source.txt destination.txt') ”(及其喜欢)是糟糕的设计。Python 是一种独立于平台的语言,使用这样的代码会破坏这个伟大的功能。
6赞 Shriraj Hegde 11/18/2022
只有第一个示例回答了这个问题。运行 shell 命令不是可移植的,也不是真正执行操作的。
14赞 Sun 3/23/2019 #14

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

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

评论

2赞 moltarze 3/31/2019
所有的答案都需要解释,哪怕是一句话。没有解释会开创不好的先例,对理解程序没有帮助。如果一个完整的 Python 菜鸟出现并看到这个,想使用它,但因为不理解而不能怎么办?您希望在回答中对所有人有所帮助。
3赞 luckydonald 4/23/2019
这难道不是缺少所有这些吗?.close()open(...)
0赞 Sun 4/24/2019
不需要 .close(),因为我们没有在任何地方存储文件指针对象(无论是 src 文件还是目标文件)。
0赞 Marcel Waldvogel 4/29/2019
AFAIK,@SundeepBorra,当文件实际关闭时,它是未定义的。建议使用(如上例所示),不要更复杂。在原始文件上使用会将整个文件读入内存,这可能太大。使用像 from 这样的标准函数,这样您和参与代码的任何人都不需要担心特殊情况。docs.python.org/3/library/io.html#io.BufferedReaderwithread()shutil
2赞 maxschlepzig 4/29/2019
yellow01 的答案相同的次优内存浪费方法。
21赞 Marc 4/25/2019 #15

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将覆盖目的地位置的任何内容

评论

0赞 Kevin 9/12/2022
为什么只有小文件?
0赞 Marc 9/13/2022
@Kevin我的错误,我应该在新鲜的时候写下原因。我将不得不再次审查并更新它,因为我不记得了 ̄_(ツ)_/ ̄
1赞 bfontaine 10/13/2022
@Kevin,因为这会加载内存中的所有内容。
8赞 Basj 12/6/2020 #16

这是一种简单的方法,无需任何模块。它与这个答案类似,但如果它是一个不适合 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赞 R J 1/2/2021 #17

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

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):

9赞 Leonardo Wildt 1/14/2021 #18

万一你已经走到了这一步。答案是您需要整个路径和文件名

import os

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

评论

0赞 Ivelin 2/1/2023
如果显示操作系统的导入,则还应导入 shutil
20赞 Ritik Banger 12/6/2022 #19

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

1. 我们可以使用 shutil 模块

代码示例:

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

除了 copyfile 之外,还有其他方法可用,比如 copy、copy2 等,但 copyfile 在性能方面是最好的,

2.我们可以使用操作系统模块

代码示例:

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

另一种方法是使用子进程,但它不是可取的,因为它是调用方法之一,并且不安全。

评论

0赞 Peter Mortensen 12/7/2022
它应该链接到文档(但不是裸链接)。
1赞 Peter Mortensen 12/7/2022
为什么我们需要一个新的答案?
0赞 Ritik Banger 12/7/2022
@PeterMortensen,添加了链接。答案会增加价值,因为其他答案要么太宽泛,要么太直接,这个答案包含可以轻松使用的有用信息。
1赞 Jeremy Davis 9/29/2023
我想你可能会感到困惑?os.system 的 python 文档指出:“子进程模块为生成新进程和检索其结果提供了更强大的工具;使用该模块比使用此功能更可取。您注意到子进程存在潜在的安全问题。但是,仅当 shell=True(默认为 shell=False)时,以及使用 os.system(未经清理的用户输入)时存在相同的秒问题时,这才成立。比起你的os.system示例,这更可取:subprocess.run([''cp', dst, src])。
1赞 JCE2423 4/1/2023 #20

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

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")

文件将打开,其数据将写入您选择的新文件。

评论

0赞 Tcll 4/24/2023
在 Linux 中,这对符号链接或硬链接是不安全的,链接的文件被重写多次
0赞 Tcll 4/25/2023 #21

对于每个人都推荐的答案,如果你不想使用标准模块,或者像我一样完全删除它们,更喜欢更多的核心 C 方法而不是写得不好的 python 方法

shutil 的工作方式是符号链接/硬链接安全的,但由于包含 while (nt, mac) 或 for (posix) 循环,用于测试 if 和 are same inos.path.normpath()srcdstshutil.copyfile()

如果您知道某些 srcdst 永远不会是同一个文件,那么这部分基本上是不需要的,否则可能会使用更快的 C 方法。
(请注意,仅仅因为一个模块可能是 C 并不意味着它本身就更快,在你使用它之前,要知道你使用的东西实际上已经写得很好了)

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

最后,如果为 False,则测试是否是带有 的符号链接,在 Windows 和 Linux 上或在 Mac 上,该符号链接在 or () 之间变化。
如果该测试解析为 True,则复制符号链接/硬链接的核心代码为:
follow_symlinkscopyfile()srcos.path.islink()nt.lstat()posix.lstat()os.lstat()Carbon.File.ResolveAliasFile(s, 0)[2]

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

posix 中的硬链接是用 完成的,尽管可以通过 调用,但它不会调用。
(可能是因为检查硬链接的唯一方法是对我们知道的第一个 inode 进行哈希映射(特别是),并假设这是硬链接目标)
posix.link()shutil.copyfile()os.link()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()