Python 강좌 / 파일 검색·복사·이동과 안전한 일괄 처리

파일 자동화는 대상 목록을 먼저 출력하는 dry-run과 실제 작업을 분리하는 방식으로 시작하는 것이 좋습니다. 이 실습은 지정 폴더의 텍스트 파일만 새 위치로 복사하고 기존 파일은 덮어쓰지 않습니다.

대상과 보존 정책 먼저 정하기

이 예제는 현재 실습 폴더 아래 copy-demo/in과 copy-demo/out만 사용하며 원본 삭제·이동은 하지 않습니다. 실행 전에 현재 폴더를 확인하고 기존 업무 폴더에서는 사용하지 마세요. 하위 폴더를 재귀 검색하지 않고 심볼릭 링크도 제외합니다.

관련 동작과 지원 조건은 파일 검색·복사·이동과 안전한 일괄 처리 관련 공식 문서에서 확인할 수 있습니다.

이동은 복사보다 원본 보존에 영향을 줄 수 있습니다. 먼저 복사·내용 검증·별도 정리 순서로 작업을 분리하면 실패 범위를 확인하기 쉽습니다. 이름 충돌이 있으면 자동 번호를 붙이기보다 오류로 멈추는 정책을 선택했습니다.

전체 예제와 실행 결과

별도의 실습 폴더에서 아래 파일을 UTF-8로 저장합니다. 가상환경을 선택한 터미널에서 python safe_copy.py 명령으로 실행합니다. macOS·Ubuntu에서 가상환경을 사용하지 않는 경우 명령 이름을 python3으로 바꿉니다.

safe_copy.py 파일의 전체 내용입니다.

import argparse
import hashlib
import shutil
from pathlib import Path

parser = argparse.ArgumentParser()
parser.add_argument("--apply", action="store_true")
args = parser.parse_args()
source = Path("copy-demo/in")
target = Path("copy-demo/out")
source.mkdir(parents=True, exist_ok=True)
sample = source / "note.txt"
if not sample.exists():
    sample.write_text("demo\n", encoding="utf-8")
files = sorted(p for p in source.glob("*.txt") if p.is_file() and not p.is_symlink())
for src in files:
    dst = target / src.name
    if dst.exists() or dst.is_symlink():
        raise FileExistsError(dst)
    print("copy", src.name)
    if args.apply:
        target.mkdir(parents=True, exist_ok=True)
        with src.open("rb") as incoming, dst.open("xb") as outgoing:
            shutil.copyfileobj(incoming, outgoing)
        digest = lambda p: hashlib.sha256(p.read_bytes()).digest()
        if digest(src) != digest(dst):
            raise RuntimeError("copy verification failed")
print("applied" if args.apply else "dry-run")

예상 결과는 다음과 같습니다.

copy note.txt
dry-run

실제 복사와 결과 검사

dry-run으로 표시된 목록을 확인한 뒤 같은 파일을 --apply로 실행합니다. xb 모드는 대상이 이미 있으면 생성을 거부합니다. 복사 뒤 SHA-256 해시를 비교해 예제 파일의 바이트가 같은지 확인합니다.

python safe_copy.py --apply

처음 실행하면 copy note.txt와 applied가 출력되고 copy-demo/out/note.txt가 생깁니다. 같은 대상에 재실행하면 FileExistsError로 멈추며 기존 결과를 덮어쓰지 않아야 합니다. 부분 복사 파일이 남으면 경로와 내용을 확인한 뒤 재시도 정책을 정합니다.

실무에서 확장할 때의 한계

예제의 해시 계산은 작은 파일 전체를 메모리에 읽습니다. 큰 파일은 블록 단위로 읽어 계산합니다. 파일 내용이 같아도 메타데이터·접근 제어·심볼릭 링크 정책까지 모두 검증되는 것은 아닙니다. 신뢰할 수 없는 사용자가 대상 디렉터리를 동시에 바꾸는 상황까지 보호하는 예제도 아닙니다.

이름 변경이나 삭제를 추가하려면 변경 전 목록, 충돌 검사, 백업과 복구 절차를 먼저 설계합니다. 실습을 끝내고 정리할 때도 실제 절대 경로가 방금 만든 copy-demo 안인지 확인하고 필요한 결과만 지웁니다.