[파이썬] shutil 디렉토리 복사 중 기존 파일 덮어쓰기 방지하기

파이썬의 shutil 라이브러리는 파일 및 디렉토리 조작에 유용한 함수를 제공합니다. 그 중 하나는 디렉토리를 복사하는 함수인 shutil.copytree()입니다. 디렉토리를 복사할 때 일반적으로 기존 파일이 있으면 덮어쓰기가 됩니다. 하지만 기존 파일을 보존하고 싶은 경우도 있습니다. 이 블로그 포스트에서는 shutil.copytree()를 사용하여 디렉토리를 복사할 때 기존 파일을 덮어쓰지 않도록 방지하는 방법을 알아보겠습니다.

문제 상황

가령, 다음과 같은 구조를 가진 디렉토리 A가 있다고 가정해봅시다.

A/
|-- file1.txt
|-- file2.txt
|-- folder1/
|   |-- file3.txt
|   |-- file4.txt
|-- folder2/
       |-- file5.txt

이때, A 디렉토리를 B 디렉토리로 복사하려고 합니다. 하지만 기존에 B 디렉토리에 같은 이름의 파일이 이미 존재한다면 그 파일은 덮어쓰게 됩니다.

해결 방법

파이썬의 shutil.copytree() 함수는 ignore인자를 통해 복사할 때 무시할 파일을 지정할 수 있습니다. 이 인자를 활용하여 기존 파일을 덮어쓰지 않도록 할 수 있습니다.

import shutil

def ignore_existing_files(directory, filenames):
    existing_files = set(filenames)
    def ignore(filename):
        return filename in existing_files
    return ignore

shutil.copytree('A', 'B', ignore=ignore_existing_files)

위의 예제에서는 ignore_existing_files()라는 사용자 정의 함수를 작성하고 이를 ignore 인자로 전달합니다. 이 함수는 복사할 디렉토리의 모든 파일 및 폴더를 가져온 후, 기존에 존재하는 파일을 ignore 함수에서 무시하도록 지정합니다.

예외 처리

복사할 디렉토리에 대상 디렉토리의 하위 디렉토리가 존재하는 경우, 해당 하위 디렉토리도 복사 대상에 포함됩니다. 따라서 다음과 같은 조건을 추가하여 예외를 처리할 수 있습니다.

import os

def ignore_existing_files(directory, filenames):
    existing_files = set(filenames)

    def ignore(filename):
        # 대상 디렉토리 내의 하위 디렉토리가 존재하는 경우 예외 처리
        if os.path.isdir(os.path.join(directory, filename)):
            return False
        return filename in existing_files

    return ignore

shutil.copytree('A', 'B', ignore=ignore_existing_files)

위의 예제에서는 if os.path.isdir(os.path.join(directory, filename)):를 사용하여 현재 파일이 디렉토리인지 확인한 다음, 디렉토리인 경우 False를 반환하여 복사 대상에서 제외시킵니다.

이제 shutil.copytree() 함수를 호출하여 디렉토리를 복사할 때 기존 파일을 덮어쓰지 않도록 할 수 있습니다.