Python shutil

LshDevLog·2026년 4월 2일

python

목록 보기
6/16
post-thumbnail
  • shutil은 파일/디렉토리를 다루는 고수준 표준 라이브러리
  • 저수준인 os보다 간편함
  • 내부적으로 os를 사용함. os 감싸서 편하게 만든 것

copy

import shutil
from pathlib import Path

print(Path('foo.txt').read_text())
shutil.copy('bar.txt', 'foo.txt')
print(Path('foo.txt').read_text())
this is foo
this is bar
  • copy(src, dst)
    • src 파일을 dst 경로로 복사
    • dst가 존재하는 파일이면 덮어씀
    • dst가 디렉토리면 해당 디렉토리 안에 동일한 파일명으로 복사됨
    • 내용 + 권한만 복사


Copy2

import shutil
from pathlib import Path
import os

print(Path('foo.txt').read_text())
shutil.copy2('bar.txt', 'foo.txt')
print(Path('foo.txt').read_text())

bar_stat = os.stat('bar.txt')
print(bar_stat.st_mtime)

foo_stat = os.stat('foo.txt')
print(foo_stat.st_mtime)
this is bar
this is bar
1774984482.7004178
1774984482.7004178
  • copy2(src, dst)
    • copy2는 내용 + 권한 + 메타데이터까지 복사(수정 시간, 접근 시간 등 stat 정보 포함)
    • dst가 존재하는 파일이면 덮어씀

copyfile

import shutil

shutil.copyfile('bar.txt', 'foo.txt')
  • 파일 내용만 복사
  • 디렉토리에는 사용 불가
  • src와 dst는 반드시 파일이어야 함
  • 권한, 메타데이터는 복사x
  • dst가 존재하면 덮어씀

copytree

import shutil
import os

shutil.copytree('./temp', './temp_copy')

print(os.listdir('./temp'))
print(os.listdir('./temp_copy'))
['bar.txt', 'foo.txt']
['bar.txt', 'foo.txt']
  • 폴더, 내부 파일 전부 복사

import shutil

shutil.copytree('src', 'dst')
FileExistsError: [WinError 183] 파일이 이미 있으므로 만들 수 없습니다: 'dst'
  • 경로가 이미 존재하면 FileExistsError에러가 발생

import shutil
import os

print(os.listdir('dst'))
shutil.copytree('src', 'dst', dirs_exist_ok=True)
print(os.listdir('dst'))
[]
['foo.txt']
  • dirs_exist_ok=True 옵션으로 dst 폴더가 있어도 에러없이 복사 가능
  • 기존 파일은 덮어쓰고 없는 파일만 추가됨(merge 방식)
  • dst에만 존재하는 파일은 삭제X

import shutil
import os

print(os.listdir('./temp'))
shutil.copytree('./temp', 'temp_copy', ignore=shutil.ignore_patterns('*.txt'))
print(os.listdir('temp_copy'))
['bar.txt', 'README.md']
['README.md']
  • ignore=shutil.ignore_patterns는 glob 패턴 기반으로 제외할 파일 지정 (*.txt 등)

move

import shutil
import os

print(os.listdir('.'))
shutil.move('./temp/foo.txt', './foo.txt')
print(os.listdir('.'))
['app.py', 'main.py', 'temp']
['app.py', 'foo.txt', 'main.py', 'temp']
  • 파일/폴더 이동

import shutil
import os

print(os.listdir('.'))
shutil.move('foo.txt', 'bar.txt')
print(os.listdir('.'))
['app.py', 'foo.txt', 'main.py', 'temp']
['app.py', 'bar.txt', 'main.py', 'temp']
  • 이름 변경도 가능
  • 같은 파일 시스템에서는 rename으로 동작(빠름)
  • 다른 파일 시스템에서는 copy + delete로 동작(느림)

rmtree

import shutil

shutil.rmtree('temp')
  • 폴더 + 내부 전부 삭제 (복구 불가)

make_archive

import shutil
import os

shutil.make_archive('backup', 'zip', 'temp')

print(os.listdir('.'))
['app.py', 'backup.zip', 'main.py', 'temp']
  • shutil.make_archive(base_name, format, root_dir, base_dir)
    - base_name: 압축 파일 경로 + 이름(확장자 제외)
    - format: zip, tar, gztar 등 다양한 포맷 지원
    • root_dir
      • 압축 작업 시작 경로
    • base_dir
      • root_dir안에서 실제로 압축할 대상

import shutil

shutil.make_archive('a', 'zip', base_dir='temp')
  • temp 폴더를 포함한 압축파일 생성

import shutil

shutil.make_archive('a', 'zip', root_dir='temp', base_dir='.')
  • temp폴더를 제외한 temp폴더내의 요소들만 압축

unpack_archive

import shutil
import os

shutil.unpack_archive('backup.zip', 'unpack_folder')

print(os.listdir('.'))
['app.py', 'backup.zip', 'main.py', 'temp', 'unpack_folder']
  • 압축 풀기

disk_usage

import shutil

total, used, free = shutil.disk_usage('.')
print(total)
print(used)
print(free)
1022992248832
720493629440
302498619392
  • 디스크 저장 공간 체크
  • total, used, free 순으로 받음
  • 바이트단위

0개의 댓글