ฉันจะคัดลอกไดเรกทอรีทั้งหมดของไฟล์ไปยังไดเรกทอรีที่มีอยู่โดยใช้ Python ได้อย่างไร


210

เรียกใช้รหัสต่อไปนี้จากไดเรกทอรีที่มีไดเรกทอรีชื่อbar(มีไฟล์อย่างน้อยหนึ่งไฟล์) และไดเรกทอรีชื่อbaz(มีไฟล์อย่างน้อยหนึ่งไฟล์) fooตรวจสอบว่ามีไม่ไดเรกทอรีชื่อ

import shutil
shutil.copytree('bar', 'foo')
shutil.copytree('baz', 'foo')

มันจะล้มเหลวด้วย:

$ python copytree_test.py 
Traceback (most recent call last):
  File "copytree_test.py", line 5, in <module>
    shutil.copytree('baz', 'foo')
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/shutil.py", line 110, in copytree
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/os.py", line 172, in makedirs
OSError: [Errno 17] File exists: 'foo'

ฉันต้องการให้มันทำงานแบบเดียวกับที่ฉันพิมพ์:

$ mkdir foo
$ cp bar/* foo/
$ cp baz/* foo/

ฉันต้องใช้shutil.copy()เพื่อคัดลอกแต่ละไฟล์bazลงในfooหรือไม่ (หลังจากที่ฉันคัดลอกเนื้อหาของ 'บาร์' ไปที่ 'foo' ด้วยshutil.copytree()หรือไม่) หรือมีวิธีที่ง่ายกว่า / ดีกว่า


1
FYI: นี่คือฟังก์ชั่น copytree เดิมเพียงคัดลอกและแก้ไขมัน :)
schlamar

3
มีปัญหาเกี่ยวกับงูหลามเกี่ยวกับการเปลี่ยนshutil.copytree()พฤติกรรมของการอนุญาตให้เขียนไปยังไดเรกทอรีที่มีอยู่ แต่มีรายละเอียดพฤติกรรมบางอย่างที่ต้องมีการตกลง
Nick Chammas

2
เพิ่งสังเกตว่ามีการใช้งานคำขอการปรับปรุงดังกล่าวข้างต้นสำหรับ Python 3.8: docs.python.org/3.8/whatsnew/3.8.html#shutil
ncoghlan

คำตอบ:


174

ข้อ จำกัด ของมาตรฐานนี้shutil.copytreeดูเหมือนว่าจะผิดพลาดและน่ารำคาญ การแก้ปัญหา:

import os, shutil
def copytree(src, dst, symlinks=False, ignore=None):
    for item in os.listdir(src):
        s = os.path.join(src, item)
        d = os.path.join(dst, item)
        if os.path.isdir(s):
            shutil.copytree(s, d, symlinks, ignore)
        else:
            shutil.copy2(s, d)

โปรดทราบว่ามันไม่สอดคล้องกับมาตรฐานทั้งหมดcopytree:

  • ไม่ให้เกียรติsymlinksและignoreพารามิเตอร์สำหรับไดเรกทอรีรากของsrcต้นไม้
  • จะไม่เพิ่มshutil.Errorข้อผิดพลาดในระดับรากของsrc;
  • ในกรณีที่มีข้อผิดพลาดระหว่างการคัดลอกของทรีย่อยก็จะเพิ่มshutil.Errorสำหรับทรีย่อยที่แทนการพยายามที่จะคัดลอก subtrees อื่น ๆ shutil.Errorและเพิ่มเดียวรวม

50
ขอบคุณ! เห็นด้วยว่าสิ่งนี้ดูเหมือนว่าจะไม่เจาะจงเลย! shutil.copytreeไม่os.makedirs(dst)ที่เริ่มต้น ไม่มีส่วนใดของรหัสที่จริงจะมีปัญหากับ dir ที่มีอยู่แล้ว สิ่งนี้จะต้องมีการเปลี่ยนแปลง อย่างน้อยก็ให้exist_ok=Falseพารามิเตอร์แก่การเรียก
cfi

6
นี่เป็นคำตอบที่ดี - แต่คำตอบของ Mital Vora ด้านล่างนั้นคุ้มค่าที่จะดู พวกเขาเรียกว่า copytree ซ้ำมากกว่าการเรียก shutil.copytree () เพราะปัญหาเดียวกันจะเกิดขึ้นเป็นอย่างอื่น อาจพิจารณาการรวมคำตอบหรืออัปเดตเป็น Mital Vora
PJeffes

4
สิ่งนี้จะล้มเหลวหากกำหนดพา ธ ที่มีไดเรกทอรีซึ่งไม่ว่างในปลายทาง อาจจะมีใครบางคนอาจจะแก้ปัญหานี้กับหาง recursion แต่นี่คือการปรับเปลี่ยนรหัสของคุณที่ทำงานdef copyTree( src, dst, symlinks=False, ignore=None): for item in os.listdir(src): s = os.path.join(src, item) d = os.path.join(dst, item) if os.path.isdir(s): if os.path.isdir(d): self.recursiveCopyTree(s, d, symlinks, ignore) else: shutil.copytree(s, d, symlinks, ignore) else: shutil.copy2(s, d)
Sojurn

8
น่ารำคาญสุด ๆ 4 ปีต่อมาและ shutil.copytree ยังคงมีข้อ จำกัด ที่โง่เง่านี้ :-(
59

5
@antred ... แต่distutils.dir_util.copy_tree()ที่ยังอาศัยอยู่ใน STDLIB ที่ไม่มีข้อ จำกัด ดังกล่าวและจริงจะทำงานตามที่คาดไว้ เนื่องจากไม่มีเหตุผลที่น่าสนใจที่จะพยายามยกเลิกการใช้งาน ( ... โดยปกติจะใช้งานไม่ได้) ของคุณเอง คำตอบของเบรนแดนอาเบลควรเป็นคำตอบที่ยอมรับได้ในขณะนี้
เซซิลแกงกะหรี่

257

นี่คือโซลูชันที่เป็นส่วนหนึ่งของไลบรารีมาตรฐาน:

from distutils.dir_util import copy_tree
copy_tree("/a/b/c", "/x/y/z")

ดูคำถามที่คล้ายกันนี้

คัดลอกเนื้อหาไดเรกทอรีไปยังไดเรกทอรีด้วยหลาม


5
นี่เป็นสิ่งที่ดีเพราะใช้ไลบรารีมาตรฐาน สามารถรักษา Symlinks, โหมดและเวลาได้เช่นกัน
itsafire

1
สังเกตเห็นข้อเสียเล็ก ๆ คือมันไม่ยอมรับdistutils.errors.DistutilsInternalError: mkpath: 'name' must be a string จำเป็นที่จะต้องPosixPath str(PosixPath)รายการสินค้าที่ต้องการสำหรับการปรับปรุง นอกเหนือจากเรื่องนี้ฉันชอบคำตอบนี้
Sun Bear

@SunBear ใช่ฉันคิดว่ามันจะเป็นกรณีของห้องสมุดอื่น ๆ ส่วนใหญ่ที่ใช้เส้นทางเป็นสตริง ส่วนหนึ่งของข้อเสียในการเลือกที่จะไม่ทำให้Pathวัตถุสืบทอดจากstrฉันคิดว่าเหมือนกับการใช้งานก่อนหน้านี้ของวัตถุเส้นทางที่มุ่งเน้นวัตถุ ..
Brendan Abel

Btw ฉันได้พบกับการขาดเอกสารของฟังก์ชั่นนี้ เป็นเอกสารที่นี่ ผู้ใช้ฟังก์ชั่นนี้เป็นคำแนะนำที่ควรระวัง
Sun Bear

1
ในขณะที่ "สาธารณะทางเทคนิค" โปรดทราบว่าผู้พัฒนา distutils ทำให้ชัดเจน (ลิงก์เดียวกับ @ SunBear's, ขอบคุณ!) ที่distutils.dir_util.copy_tree()ถือเป็นรายละเอียดการดำเนินการของ distutils และไม่แนะนำให้ใช้เพื่อสาธารณะ ทางออกที่แท้จริงควรจะได้shutil.copytree()รับการปรับปรุง / ขยายให้ทำตัวเหมือนdistutils.dir_util.copy_tree()แต่ไม่มีข้อบกพร่อง ในระหว่างนี้ฉันจะใช้ฟังก์ชั่นตัวช่วยที่กำหนดเองคล้ายกับบางส่วนของคำตอบอื่น ๆ
Boris Dalstein

61

ในการปรับปรุงเล็กน้อยในคำตอบของ atzz กับฟังก์ชั่นที่ฟังก์ชั่นดังกล่าวพยายามที่จะคัดลอกไฟล์จากแหล่งที่มาไปยังปลายทางเสมอ

def copytree(src, dst, symlinks=False, ignore=None):
    if not os.path.exists(dst):
        os.makedirs(dst)
    for item in os.listdir(src):
        s = os.path.join(src, item)
        d = os.path.join(dst, item)
        if os.path.isdir(s):
            copytree(s, d, symlinks, ignore)
        else:
            if not os.path.exists(d) or os.stat(s).st_mtime - os.stat(d).st_mtime > 1:
                shutil.copy2(s, d)

ในการดำเนินการข้างต้นของฉัน

  • การสร้างไดเรกทอรีผลลัพธ์หากยังไม่มีอยู่
  • ทำสำเนาไดเรกทอรีโดยเรียกวิธีการของตัวเองซ้ำ ๆ
  • เมื่อเรามาถึงการคัดลอกไฟล์ฉันจะตรวจสอบว่าไฟล์นั้นได้รับการแก้ไขหรือไม่เราควรคัดลอกเท่านั้น

ฉันใช้ฟังก์ชั่นด้านบนพร้อมกับสร้าง scons มันช่วยฉันได้มากเหมือนทุกครั้งที่ฉันรวบรวมฉันอาจไม่จำเป็นต้องคัดลอกไฟล์ทั้งหมด .. แต่เฉพาะไฟล์ที่ถูกแก้ไข


4
ดียกเว้นว่าคุณมี symlink และเพิกเฉยเป็นอาร์กิวเมนต์ แต่จะถูกละเว้น
Matthew Alpert

มันเป็นที่น่าสังเกตว่า st_mtime เมล็ดสามารถเป็นหยาบ 2 วินาทีบน FAT filesystems docs.python.org/2/library/os.html การใช้รหัสนี้ในบริบทที่การอัพเดทเกิดขึ้นอย่างรวดเร็วคุณอาจพบว่าการแทนที่ไม่ได้เกิดขึ้น
dgh

มีข้อผิดพลาดในบรรทัดที่สองถึงครั้งสุดท้ายควรเป็น: if not os.path.exists(d) or os.stat(s).st_mtime - os.stat(d).st_mtime > 1:
mpderbec

34

การผสานที่ได้รับแรงบันดาลใจจาก atzz และ Mital Vora:

#!/usr/bin/python
import os
import shutil
import stat
def copytree(src, dst, symlinks = False, ignore = None):
  if not os.path.exists(dst):
    os.makedirs(dst)
    shutil.copystat(src, dst)
  lst = os.listdir(src)
  if ignore:
    excl = ignore(src, lst)
    lst = [x for x in lst if x not in excl]
  for item in lst:
    s = os.path.join(src, item)
    d = os.path.join(dst, item)
    if symlinks and os.path.islink(s):
      if os.path.lexists(d):
        os.remove(d)
      os.symlink(os.readlink(s), d)
      try:
        st = os.lstat(s)
        mode = stat.S_IMODE(st.st_mode)
        os.lchmod(d, mode)
      except:
        pass # lchmod not available
    elif os.path.isdir(s):
      copytree(s, d, symlinks, ignore)
    else:
      shutil.copy2(s, d)
  • พฤติกรรมเช่นเดียวกับshutil.copytreeพร้อมsymlinksและละเว้นพารามิเตอร์
  • สร้างโครงสร้างปลายทางของไดเรกทอรีหากไม่มีอยู่จริง
  • จะไม่ล้มเหลวหากdstมีอยู่แล้ว

นี่คือเร็วกว่าโซลูชันเดิมมากเมื่อทำรังไดเรกทอรีลึก ขอบคุณ
Kashif

คุณนิยามฟังก์ชันที่ชื่อ 'ละเว้น' ในโค้ดที่อื่นหรือไม่?
KenV99

คุณสามารถกำหนดฟังก์ชั่นใด ๆ ที่มีชื่อที่คุณชอบก่อนที่จะเรียกฟังก์ชั่น copytree ฟังก์ชั่นนี้ (ซึ่งอาจเป็นนิพจน์แลมบ์ดา) รับสองอาร์กิวเมนต์: ชื่อไดเรกทอรีและไฟล์ที่อยู่ในนั้นควรคืนค่าไฟล์ที่ละเว้นได้
Cyrille Pontvieux

[x for x in lst if x not in excl]สิ่งนี้ไม่ได้เหมือนกับ copytree ซึ่งใช้การจับคู่รูปแบบกลม en.wikipedia.org/wiki/Glob_(programming)
Konstantin Schubert

2
มันเยี่ยมมาก การเพิกเฉยไม่ได้ถูกใช้อย่างถูกต้องในคำตอบข้างต้น
Keith Holliday

21

Python 3.8 แนะนำdirs_exist_okอาร์กิวเมนต์ไปที่shutil.copytree:

คัดลอกทรีไดเรกทอรีทั้งหมดซ้ำ ๆ ที่srcไปยังไดเรกทอรีที่ชื่อdstและส่งกลับไดเรกทอรีปลายทาง dirs_exist_okบอกให้ยกข้อยกเว้นในกรณีdstหรือไดเรกทอรีหลักที่ขาดหายไปนั้นมีอยู่แล้ว

ดังนั้นด้วย Python 3.8+ สิ่งนี้น่าจะได้ผล:

import shutil

shutil.copytree('bar', 'foo')
shutil.copytree('baz', 'foo', dirs_exist_ok=True)

dirs_exist_ok=Falseโดยค่าเริ่มต้นใน copytree ความพยายามในการคัดลอกครั้งแรกจะล้มเหลวหรือไม่
Jay

1
@Jay เฉพาะในกรณีที่มีไดเรกทอรีอยู่แล้ว ฉันdirs_exist_okออกจากการโทรครั้งแรกเพื่อแสดงความแตกต่าง (และเนื่องจากไดเรกทอรียังไม่มีอยู่ในตัวอย่างของ OP) แต่แน่นอนคุณสามารถใช้มันได้หากคุณต้องการ
คริส

ขอบคุณถ้าคุณเพิ่มความคิดเห็นที่อยู่ใกล้กับสำเนาแรกผมคิดว่ามันจะทำให้มันชัดเจน :)
เจ

7

เอกสารระบุอย่างชัดเจนว่าไม่ควรมีไดเรกทอรีปลายทาง :

ไดเรกทอรีปลายทางที่ตั้งชื่อตามdstต้องไม่มีอยู่จริง มันจะถูกสร้างขึ้นเช่นเดียวกับไดเรกทอรีหลักที่ขาดหายไป

ฉันคิดว่าทางออกที่ดีที่สุดของคุณคือos.walkไดเรกทอรีที่สองและตามมาทั้งหมดcopy2ไดเรกทอรีและไฟล์และทำเพิ่มเติมcopystatสำหรับไดเรกทอรี copytreeท้ายที่สุดนั่นคือสิ่งที่อธิบายไว้ในเอกสารอย่างแม่นยำ หรือคุณอาจจะcopyและcopystatแต่ละไดเรกทอรี / ไฟล์และแทนos.listdiros.walk


1

นี่เป็นแรงบันดาลใจจากคำตอบที่ดีที่สุดจาก atzz ฉันเพิ่งเพิ่มตรรกะไฟล์ / โฟลเดอร์แทน ดังนั้นจึงไม่ได้ผสาน แต่ลบไฟล์ / โฟลเดอร์ที่มีอยู่และคัดลอกใหม่:

import shutil
import os
def copytree(src, dst, symlinks=False, ignore=None):
    for item in os.listdir(src):
        s = os.path.join(src, item)
        d = os.path.join(dst, item)
        if os.path.exists(d):
            try:
                shutil.rmtree(d)
            except Exception as e:
                print e
                os.unlink(d)
        if os.path.isdir(s):
            shutil.copytree(s, d, symlinks, ignore)
        else:
            shutil.copy2(s, d)
    #shutil.rmtree(src)

ยกเลิกการคอมเม้นต์ rmtree เพื่อให้เป็นฟังก์ชันย้าย


0

นี่คืองานเดียวกันของฉันในเวอร์ชั่น ::

import os, glob, shutil

def make_dir(path):
    if not os.path.isdir(path):
        os.mkdir(path)


def copy_dir(source_item, destination_item):
    if os.path.isdir(source_item):
        make_dir(destination_item)
        sub_items = glob.glob(source_item + '/*')
        for sub_item in sub_items:
            copy_dir(sub_item, destination_item + '/' + sub_item.split('/')[-1])
    else:
        shutil.copy(source_item, destination_item)

0

distutils.file_util.copy_fileนี่คือรุ่นแรงบันดาลใจจากกระทู้นี้ที่เลียนแบบใกล้ชิดมากขึ้น

updateonlyเป็นบูลถ้าเป็น True จะคัดลอกเฉพาะไฟล์ที่มีการแก้ไขวันที่ใหม่กว่าไฟล์ที่มีอยู่ในdstเว้นแต่ว่าจะมีการระบุไว้ในforceupdateที่ที่จะคัดลอกโดยไม่คำนึงถึง

ignoreและforceupdateคาดว่ารายชื่อของชื่อไฟล์หรือโฟลเดอร์ / ชื่อไฟล์เทียบกับ srcและยอมรับ Unix สไตล์คล้ายกับสัญลักษณ์แทนหรือglobfnmatch

ฟังก์ชันส่งคืนรายการไฟล์ที่คัดลอก (หรือจะถูกคัดลอกdryrunถ้าเป็น True)

import os
import shutil
import fnmatch
import stat
import itertools

def copyToDir(src, dst, updateonly=True, symlinks=True, ignore=None, forceupdate=None, dryrun=False):

    def copySymLink(srclink, destlink):
        if os.path.lexists(destlink):
            os.remove(destlink)
        os.symlink(os.readlink(srclink), destlink)
        try:
            st = os.lstat(srclink)
            mode = stat.S_IMODE(st.st_mode)
            os.lchmod(destlink, mode)
        except OSError:
            pass  # lchmod not available
    fc = []
    if not os.path.exists(dst) and not dryrun:
        os.makedirs(dst)
        shutil.copystat(src, dst)
    if ignore is not None:
        ignorepatterns = [os.path.join(src, *x.split('/')) for x in ignore]
    else:
        ignorepatterns = []
    if forceupdate is not None:
        forceupdatepatterns = [os.path.join(src, *x.split('/')) for x in forceupdate]
    else:
        forceupdatepatterns = []
    srclen = len(src)
    for root, dirs, files in os.walk(src):
        fullsrcfiles = [os.path.join(root, x) for x in files]
        t = root[srclen+1:]
        dstroot = os.path.join(dst, t)
        fulldstfiles = [os.path.join(dstroot, x) for x in files]
        excludefiles = list(itertools.chain.from_iterable([fnmatch.filter(fullsrcfiles, pattern) for pattern in ignorepatterns]))
        forceupdatefiles = list(itertools.chain.from_iterable([fnmatch.filter(fullsrcfiles, pattern) for pattern in forceupdatepatterns]))
        for directory in dirs:
            fullsrcdir = os.path.join(src, directory)
            fulldstdir = os.path.join(dstroot, directory)
            if os.path.islink(fullsrcdir):
                if symlinks and dryrun is False:
                    copySymLink(fullsrcdir, fulldstdir)
            else:
                if not os.path.exists(directory) and dryrun is False:
                    os.makedirs(os.path.join(dst, dir))
                    shutil.copystat(src, dst)
        for s,d in zip(fullsrcfiles, fulldstfiles):
            if s not in excludefiles:
                if updateonly:
                    go = False
                    if os.path.isfile(d):
                        srcdate = os.stat(s).st_mtime
                        dstdate = os.stat(d).st_mtime
                        if srcdate > dstdate:
                            go = True
                    else:
                        go = True
                    if s in forceupdatefiles:
                        go = True
                    if go is True:
                        fc.append(d)
                        if not dryrun:
                            if os.path.islink(s) and symlinks is True:
                                copySymLink(s, d)
                            else:
                                shutil.copy2(s, d)
                else:
                    fc.append(d)
                    if not dryrun:
                        if os.path.islink(s) and symlinks is True:
                            copySymLink(s, d)
                        else:
                            shutil.copy2(s, d)
    return fc

0

โซลูชันก่อนหน้านี้มีปัญหาบางอย่างที่srcอาจเขียนทับได้dstโดยไม่มีการแจ้งเตือนหรือข้อยกเว้น

ฉันเพิ่มpredict_errorวิธีการทำนายข้อผิดพลาดก่อนทำสำเนา copytreeส่วนใหญ่ขึ้นอยู่กับรุ่นของ Cyrille Pontvieux

การใช้predict_errorเพื่อคาดการณ์ข้อผิดพลาดทั้งหมดในตอนแรกนั้นดีที่สุดเว้นแต่ว่าคุณต้องการดูข้อยกเว้นที่เพิ่มขึ้นทีละตัวเมื่อดำเนินการcopytreeจนกระทั่งแก้ไขข้อผิดพลาดทั้งหมด

def predict_error(src, dst):  
    if os.path.exists(dst):
        src_isdir = os.path.isdir(src)
        dst_isdir = os.path.isdir(dst)
        if src_isdir and dst_isdir:
            pass
        elif src_isdir and not dst_isdir:
            yield {dst:'src is dir but dst is file.'}
        elif not src_isdir and dst_isdir:
            yield {dst:'src is file but dst is dir.'}
        else:
            yield {dst:'already exists a file with same name in dst'}

    if os.path.isdir(src):
        for item in os.listdir(src):
            s = os.path.join(src, item)
            d = os.path.join(dst, item)
            for e in predict_error(s, d):
                yield e


def copytree(src, dst, symlinks=False, ignore=None, overwrite=False):
    '''
    would overwrite if src and dst are both file
    but would not use folder overwrite file, or viceverse
    '''
    if not overwrite:
        errors = list(predict_error(src, dst))
        if errors:
            raise Exception('copy would overwrite some file, error detail:%s' % errors)

    if not os.path.exists(dst):
        os.makedirs(dst)
        shutil.copystat(src, dst)
    lst = os.listdir(src)
    if ignore:
        excl = ignore(src, lst)
        lst = [x for x in lst if x not in excl]
    for item in lst:
        s = os.path.join(src, item)
        d = os.path.join(dst, item)
        if symlinks and os.path.islink(s):
            if os.path.lexists(d):
                os.remove(d)
            os.symlink(os.readlink(s), d)
            try:
                st = os.lstat(s)
                mode = stat.S_IMODE(st.st_mode)
                os.lchmod(d, mode)
            except:
                pass  # lchmod not available
        elif os.path.isdir(s):
            copytree(s, d, symlinks, ignore)
        else:
            if not overwrite:
                if os.path.exists(d):
                    continue
            shutil.copy2(s, d)

0

นี่คือปัญหาของฉันในการผ่าน ฉันแก้ไขซอร์สโค้ดสำหรับ copytree เพื่อให้การทำงานดั้งเดิม แต่ตอนนี้ไม่มีข้อผิดพลาดเกิดขึ้นเมื่อไดเรกทอรีมีอยู่แล้ว ฉันเปลี่ยนมันด้วยดังนั้นมันจึงไม่เขียนทับไฟล์ที่มีอยู่ แต่ควรเก็บทั้งสองสำเนาไว้หนึ่งไฟล์ที่มีชื่อที่ปรับเปลี่ยนเนื่องจากนี่เป็นสิ่งสำคัญสำหรับแอปพลิเคชันของฉัน

import shutil
import os


def _copytree(src, dst, symlinks=False, ignore=None):
    """
    This is an improved version of shutil.copytree which allows writing to
    existing folders and does not overwrite existing files but instead appends
    a ~1 to the file name and adds it to the destination path.
    """

    names = os.listdir(src)
    if ignore is not None:
        ignored_names = ignore(src, names)
    else:
        ignored_names = set()

    if not os.path.exists(dst):
        os.makedirs(dst)
        shutil.copystat(src, dst)
    errors = []
    for name in names:
        if name in ignored_names:
            continue
        srcname = os.path.join(src, name)
        dstname = os.path.join(dst, name)
        i = 1
        while os.path.exists(dstname) and not os.path.isdir(dstname):
            parts = name.split('.')
            file_name = ''
            file_extension = parts[-1]
            # make a new file name inserting ~1 between name and extension
            for j in range(len(parts)-1):
                file_name += parts[j]
                if j < len(parts)-2:
                    file_name += '.'
            suffix = file_name + '~' + str(i) + '.' + file_extension
            dstname = os.path.join(dst, suffix)
            i+=1
        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:
                shutil.copy2(srcname, dstname)
        except (IOError, os.error) as why:
            errors.append((srcname, dstname, str(why)))
        # catch the Error from the recursive copytree so that we can
        # continue with other files
        except BaseException as err:
            errors.extend(err.args[0])
    try:
        shutil.copystat(src, dst)
    except WindowsError:
        # can't copy file access times on Windows
        pass
    except OSError as why:
        errors.extend((src, dst, str(why)))
    if errors:
        raise BaseException(errors)

0

ลองสิ่งนี้:

import os,shutil

def copydir(src, dst):
  h = os.getcwd()
  src = r"{}".format(src)
  if not os.path.isdir(dst):
     print("\n[!] No Such directory: ["+dst+"] !!!")
     exit(1)

  if not os.path.isdir(src):
     print("\n[!] No Such directory: ["+src+"] !!!")
     exit(1)
  if "\\" in src:
     c = "\\"
     tsrc = src.split("\\")[-1:][0]
  else:
    c = "/"
    tsrc = src.split("/")[-1:][0]

  os.chdir(dst)
  if os.path.isdir(tsrc):
    print("\n[!] The Directory Is already exists !!!")
    exit(1)
  try:
    os.mkdir(tsrc)
  except WindowsError:
    print("\n[!] Error: In[ {} ]\nPlease Check Your Dirctory Path !!!".format(src))
    exit(1)
  os.chdir(h)
  files = []
  for i in os.listdir(src):
    files.append(src+c+i)
  if len(files) > 0:
    for i in files:
        if not os.path.isdir(i):
            shutil.copy2(i, dst+c+tsrc)

  print("\n[*] Done ! :)")

copydir("c:\folder1", "c:\folder2")

0

นี่คือเวอร์ชันที่คาดว่าจะpathlib.Pathเป็นอินพุต

# Recusively copies the content of the directory src to the directory dst.
# If dst doesn't exist, it is created, together with all missing parent directories.
# If a file from src already exists in dst, the file in dst is overwritten.
# Files already existing in dst which don't exist in src are preserved.
# Symlinks inside src are copied as symlinks, they are not resolved before copying.
#
def copy_dir(src, dst):
    dst.mkdir(parents=True, exist_ok=True)
    for item in os.listdir(src):
        s = src / item
        d = dst / item
        if s.is_dir():
            copy_dir(s, d)
        else:
            shutil.copy2(str(s), str(d))

โปรดทราบว่าฟังก์ชั่นนี้ต้องใช้ Python 3.6 ซึ่งเป็นรุ่นแรกของ Python ที่os.listdir()รองรับวัตถุคล้ายพา ธ เป็นอินพุต หากคุณต้องการที่จะสนับสนุนรุ่นก่อนหน้านี้ของงูใหญ่คุณสามารถแทนที่โดยlistdir(src)listdir(str(src))


-2

ฉันจะสมมติวิธีที่เร็วและง่ายที่สุดที่จะมีหลามโทรคำสั่งของระบบ ...

ตัวอย่าง..

import os
cmd = '<command line call>'
os.system(cmd)

Tar และ gzip ไดเรกทอรี .... unzip และ untar ไดเรกทอรีในสถานที่ที่ต้องการ

ย่ะ?


หากคุณกำลังทำงานใน windows ... ดาวน์โหลด 7zip .. และใช้บรรทัดคำสั่งสำหรับสิ่งนั้น ... เพียงแค่คำแนะนำ
เคอร์บี้

31
คำสั่งระบบควรเป็นทางเลือกสุดท้าย ควรใช้ไลบรารีมาตรฐานทุกครั้งที่ทำได้เพื่อให้โค้ดของคุณพกพาได้
jathanism
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.