Python에서 재귀 적으로 파일 또는 디렉토리 복사


116

파이썬에는 파일 복사 기능 (예 shutil.copy:)과 디렉터리 복사 기능 (예 :)이있는 것 같지만 shutil.copytree둘 다 처리하는 기능을 찾지 못했습니다. 물론 파일이나 디렉토리를 복사할지 여부를 확인하는 것은 사소한 일이지만 이상한 누락처럼 보입니다.

실제로 unix cp -r명령 처럼 작동하는 표준 기능이 없습니까? 즉, 디렉토리와 파일을 모두 지원하고 재귀 적으로 복사합니다. 파이썬에서이 문제를 해결하는 가장 우아한 방법은 무엇입니까?


3
예, 이것은 엉망입니다. 기본 시스템 호출을 반영하려고 시도함으로써 Python이 가시적 인 인터페이스를 악화시키는 곳 중 하나입니다. 파일 복사와 트리 복사 사이를 전환하는 것은 어렵지 않지만 필요하지는 않았습니다. copytree단일 파일을 복사 할 수 있도록 Python 버그 추적기에 개선 요청을 제출할 수 있습니까?
bobince

답변:


142

먼저을 호출 shutil.copytree하고 예외가 발생하면를 사용하여 다시 시도하십시오 shutil.copy.

import shutil, errno

def copyanything(src, dst):
    try:
        shutil.copytree(src, dst)
    except OSError as exc: # python >2.5
        if exc.errno == errno.ENOTDIR:
            shutil.copy(src, dst)
        else: raise

18
src가 이와 같은 예외를 포착하는 대신 os.path.isdir (src)를 사용하여 디렉토리인지 확인하는 것이 훨씬 더 깨끗할 것이라고 생각합니다. 아니면 여기에 예외를 사용해야하는 특별한 이유가 있습니까?
pafcu

31
1) 파이썬 세계에서는 EAFP (허가보다 용서를 구하는 것이 더 쉽다)가 LBYL (도약하기 전에 살펴보기)보다 선호되기 때문입니다. 새롭다 고 생각되는 경우 이에 대한 링크를 제공 할 수 있습니다. 2) 라이브러리 함수는 이미 간접적으로 확인하고 있는데, 왜 확인을 복제합니까? 3) shutil.copytree앞으로 두 경우 모두 기능을 개선하고 관리하는 것을 막을 수있는 것은 없습니다 . 4) 예외는 파이썬에서 그다지 예외적이지 않습니다. 예를 들어, 반복은 StopIteration 예외를 발생시켜 중지합니다.
tzot 2010 년

2
이 경우 예외를 처리하는 데는 6 줄이 걸리고 유형을 확인하는 데는 4 줄이 걸립니다. 많지는 않지만 결국 합산됩니다. 또한, 당신이 말했듯이 카피 트리는 언젠가는 파일도 잘 지원할 것입니다. 그러나 그 구현이 어떻게 될지 말하기는 불가능합니다. 복사가 작동하는 상황에서 예외가 발생할 수 있습니까? 이 경우 추가 된 기능 때문에 내 코드가 갑자기 작동을 멈출 것입니다. 하지만 당신 말이 맞을 것입니다. 파이썬에서 예외는 꽤 흔합니다. 제가 매우 짜증나는 일이라고 생각합니다.하지만 아마 익숙해지지 않았기 때문일 것입니다
pafcu

5
실제로 예외는이 경우 한 가지 분명한 객관적 이점이 있습니다. 유형이 검사와 올바른 함수 호출 사이에 변경 될 가능성은 거의 없지만 전적으로 가능합니다.
pafcu 2010 년

2
제 개인적인 의견으로는 예외에 핵심 기능을 추가하는 것은 나쁜 습관이며 사용하는 언어는 중요하지 않습니다. 많은 개발자가 검색하지 않는 곳에 기능을 배치합니다. 또한 주석을 작성하지 않으면 경험이 부족한 파이썬 개발자는이 재 시도의 목적이 무엇인지 실제로 이해하지 못할 것입니다. 여기와 같은 사소한 것에 대한 주석을 추가해야하는 경우 코드 스타일에 문제가있는 것입니다. 마지막으로 if / else를 작성하면 코드를 훨씬 쉽게 읽을 수 있습니다.
this.myself 2015 년

7

Tzotgns 답변 을 추가하려면 파일과 폴더를 재귀 적으로 복사하는 다른 방법이 있습니다. (Python 3.X)

import os, shutil

root_src_dir = r'C:\MyMusic'    #Path/Location of the source directory
root_dst_dir = 'D:MusicBackUp'  #Path to the destination folder

for src_dir, dirs, files in os.walk(root_src_dir):
    dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
    if not os.path.exists(dst_dir):
        os.makedirs(dst_dir)
    for file_ in files:
        src_file = os.path.join(src_dir, file_)
        dst_file = os.path.join(dst_dir, file_)
        if os.path.exists(dst_file):
            os.remove(dst_file)
        shutil.copy(src_file, dst_dir)

처음이고 파일과 폴더를 재귀 적으로 복사하는 방법을 모른다면 도움이 되었기를 바랍니다.


3

shutil.copyshutil.copy2파일을 복사합니다.

shutil.copytree모든 파일과 모든 하위 폴더가있는 폴더를 복사합니다. 파일을 복사하는 데 shutil.copytree사용 shutil.copy2하고 있습니다.

아날로그 그래서 cp -r당신이 말하는 인 shutil.copytree때문에 cp -r대상 복사 폴더와 파일 / 하위 폴더 좋아 shutil.copytree. -r cp복사 파일 없이는 좋아 shutil.copy하고 shutil.copy2합니다.


1
나는 당신이 질문을 이해했다고 생각하지 않습니다. 시도해보십시오 shutil.copytree('C:\myfile.txt', 'C:\otherfile'). 작동하지 않습니다. 그게 OP가 요구했던 것입니다 ... 7 년 전.
Jean-François Corbett

물론 작동하지 않습니다. cp가 폴더에서 작동하지 않는 것처럼. 특별한 옵션이 필요합니다. copy와 copytree는 복사를 처리하는 가장 좋은 방법입니다. 카피 트리가 타겟과 파일을 만들 수 있다면 실수하기 쉽습니다. Linux와 Python 모두에서 무엇을 목표로하는지 알아야합니다. 어렵습니다. 게다가 다른 누군가가 여기에 댓글을 달았지만 질문과 답변을보고 대답을 거부 할 수 없었습니다. 우아한 방법은 제어 할 수없는 범용 사본이 아니라 원하는 작업을 아는 것입니다.
gms

2

Unix cp는 '디렉토리와 파일을 모두 지원'하지 않습니다.

betelgeuse:tmp james$ cp source/ dest/
cp: source/ is a directory (not copied).

cp가 디렉토리를 복사하도록하려면 '-r'플래그를 사용하여 cp에게 디렉토리임을 수동으로 알려야합니다.

하지만 여기에 약간의 연결이 끊어졌습니다 cp -r. 소스가 파일 이름을 전달하면 행복하게 단일 파일 만 복사합니다. 카피 트리는 그렇지 않습니다.


2
docs.python.org/library/shutil.html 에는 일반 파일, 심볼릭 링크 및 디렉토리 처리를 보여주는 copytree () 코드가 포함되어 있습니다.
James Polley

1
이 답변은 질문을 해결하지 않습니다. 답변이 아닌 댓글이어야합니다.
Jean-François Corbett

0

나는 copy_tree가 당신이 찾고있는 것이라고 생각합니다.


-2

파이썬 shutil.copytree 메소드는 엉망입니다. 올바르게 작동하는 작업을 수행했습니다.

def copydirectorykut(src, dst):
    os.chdir(dst)
    list=os.listdir(src)
    nom= src+'.txt'
    fitx= open(nom, 'w')

    for item in list:
        fitx.write("%s\n" % item)
    fitx.close()

    f = open(nom,'r')
    for line in f.readlines():
        if "." in line:
            shutil.copy(src+'/'+line[:-1],dst+'/'+line[:-1])
        else:
            if not os.path.exists(dst+'/'+line[:-1]):
                os.makedirs(dst+'/'+line[:-1])
                copydirectorykut(src+'/'+line[:-1],dst+'/'+line[:-1])
            copydirectorykut(src+'/'+line[:-1],dst+'/'+line[:-1])
    f.close()
    os.remove(nom)
    os.chdir('..')

1
이 코드는 작업 개별 파일 검사 (덮어 쓰기 문제 검사)에는 좋지만 'zip'과 같은 바이너리 파일에는 작동하지 않습니다. 한 줄씩 읽기 / 쓰기 대신 간단한 파이썬 파일 복사를 사용하지 않는 이유는 무엇입니까?
notilas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.