Python의os.walk
는 디렉토리와 그 내용을 재귀적으로 탐색하는 강력한 도구입니다. 이 함수를 활용하면 지정한 디렉토리의 모든 하위 디렉토리와 파일을 효율적으로 가져올 수 있습니다. 본 기사에서는 os.walk
의 기본적인 사용법부터 실용적인 응용 예제까지 포괄적으로 설명합니다. 이를 통해 디렉토리 작업을 포함하는 작업을 더 효율적으로 처리할 수 있을 것입니다.
os.walk란 무엇인가
os.walk
는 Python의 표준 라이브러리os
모듈에 포함된 함수로, 지정한 디렉토리를 재귀적으로 탐색하고 그 디렉토리 내의 파일 및 하위 디렉토리 목록을 생성합니다. 이 함수를 사용하면 복잡한 디렉토리 구조를 쉽게 탐색할 수 있으며, 파일 및 폴더 목록을 가져오는 데 매우 유용합니다.
os.walk의 동작 원리
os.walk
는 제너레이터로 동작하며, 다음 세 가지 요소를 튜플로 반환합니다.
- 디렉토리 경로 (
dirpath
)
현재 탐색 중인 디렉토리의 경로를 나타냅니다. - 하위 디렉토리 목록 (
dirnames
)
현재 디렉토리 내의 하위 디렉토리 이름 목록입니다. - 파일 목록 (
filenames
)
현재 디렉토리 내의 파일 이름 목록입니다.
특징
- 재귀적 탐색: 지정된 디렉토리의 하위 디렉토리를 자동으로 탐색합니다.
- 순서: 디렉토리 계층을 상위에서 하위로 또는 하위에서 상위로 처리하는 설정이 가능합니다(
topdown=True/False
). - 효율성: 필요한 정보를 즉시 생성하여 메모리 효율이 좋습니다.
용도
- 파일 이름 검색
- 특정 확장자를 가진 파일 목록 작성
- 하위 디렉토리 크기 계산
- 백업 또는 이동 작업 자동화
기본적인 사용법
os.walk
를 사용하면 지정된 디렉토리 아래의 파일 및 폴더를 쉽게 가져올 수 있습니다. 아래는 기본적인 코드 예제입니다.
코드 예제
import os
# 대상 디렉토리 지정
target_directory = "/path/to/your/directory"
# os.walk 사용하여 디렉토리 탐색
for dirpath, dirnames, filenames in os.walk(target_directory):
print(f"현재 경로: {dirpath}")
print(f"디렉토리: {dirnames}")
print(f"파일: {filenames}")
print("-" * 40)
출력 예제
디렉토리 구조가 아래와 같다고 가정합니다:
/path/to/your/directory
├── file1.txt
├── file2.txt
├── subdir1
│ └── file3.txt
└── subdir2
└── file4.txt
이 경우, os.walk
를 실행하면 다음과 같은 출력이 나옵니다:
현재 경로: /path/to/your/directory
디렉토리: ['subdir1', 'subdir2']
파일: ['file1.txt', 'file2.txt']
----------------------------------------
현재 경로: /path/to/your/directory/subdir1
디렉토리: []
파일: ['file3.txt']
----------------------------------------
현재 경로: /path/to/your/directory/subdir2
디렉토리: []
파일: ['file4.txt']
----------------------------------------
설명
- dirpath: 현재 탐색 중인 디렉토리의 경로입니다.
- dirnames: 현재 디렉토리 내에 존재하는 하위 디렉토리 이름 목록입니다.
- filenames: 현재 디렉토리 내에 존재하는 파일 이름 목록입니다.
주의 사항
os.walk
는 지정한 디렉토리가 존재하지 않으면 에러를 발생시키므로, 사전에 디렉토리 존재 여부를 확인하는 것이 안전합니다.
파일과 디렉토리 분기 처리
os.walk
를 사용하면 디렉토리 내의 파일과 폴더를 효율적으로 분류할 수 있습니다. 각 항목에 대해 다른 처리를 적용하고 싶을 때, 분기 처리를 추가하기만 하면 쉽게 구현할 수 있습니다.
코드 예제
다음은 파일과 디렉토리를 분기하여 각각 다른 처리를 수행하는 예제입니다:
import os
# 대상 디렉토리 지정
target_directory = "/path/to/your/directory"
# 디렉토리 탐색 및 분기 처리
for dirpath, dirnames, filenames in os.walk(target_directory):
# 하위 디렉토리에 대한 처리
for dirname in dirnames:
subdir_path = os.path.join(dirpath, dirname)
print(f"디렉토리: {subdir_path}")
# 파일에 대한 처리
for filename in filenames:
file_path = os.path.join(dirpath, filename)
print(f"파일: {file_path}")
출력 예제
디렉토리 구조가 아래와 같은 경우:
/path/to/your/directory
├── file1.txt
├── file2.txt
├── subdir1
│ └── file3.txt
└── subdir2
└── file4.txt
출력은 다음과 같습니다:
디렉토리: /path/to/your/directory/subdir1
디렉토리: /path/to/your/directory/subdir2
파일: /path/to/your/directory/file1.txt
파일: /path/to/your/directory/file2.txt
파일: /path/to/your/directory/subdir1/file3.txt
파일: /path/to/your/directory/subdir2/file4.txt
코드 설명
os.path.join
:dirpath
와dirname
또는filename
을 결합하여 절대 경로를 생성합니다.- 디렉토리 처리 (
for dirname in dirnames
): 디렉토리에 대해 특정 작업(예: 디렉토리 생성 일시 가져오기)을 수행할 수 있습니다. - 파일 처리 (
for filename in filenames
): 각 파일에 대해 특정 작업(예: 파일 크기 가져오기)을 수행할 수 있습니다.
응용 예제
- 하위 디렉토리 이름 목록을 작성하여 관리하기
- 특정 이름 규칙을 따른 파일을 추출하여 처리하기
- 파일 크기나 생성 일시를 기준으로 필터링 작업 수행하기
특정 확장자를 가진 파일을 검색하는 방법
os.walk
를 사용하면 특정 확장자를 가진 파일을 쉽게 검색할 수 있습니다. 예를 들어 .txt
나 .jpg
와 같은 특정 형식의 파일을 효율적으로 추출할 수 있습니다.
코드 예제
다음은 .txt
확장자를 가진 파일을 검색하여 그 경로를 출력하는 코드 예제입니다:
import os
# 대상 디렉토리 지정
target_directory = "/path/to/your/directory"
# 검색할 확장자 지정
target_extension = ".txt"
# 특정 확장자를 가진 파일 검색
for dirpath, dirnames, filenames in os.walk(target_directory):
for filename in filenames:
if filename.endswith(target_extension):
file_path = os.path.join(dirpath, filename)
print(f"찾음: {file_path}")
출력 예제
디렉토리 구조가 아래와 같은 경우:
/path/to/your/directory
├── file1.txt
├── file2.doc
├── subdir1
│ └── notes.txt
└── subdir2
└── image.png
출력은 다음과 같습니다:
찾음: /path/to/your/directory/file1.txt
찾음: /path/to/your/directory/subdir1/notes.txt
코드 설명
filename.endswith(target_extension)
: 파일 이름이 지정된 확장자로 끝날 경우 True를 반환합니다. 이를 이용해 특정 파일 형식을 필터링합니다.os.path.join
: 전체 경로를 생성하기 위해 사용합니다.
여러 확장자 검색하는 방법
여러 확장자를 검색하고자 할 때는 조건을 변경합니다.
# 검색할 확장자를 리스트로 지정
target_extensions = [" .txt", ".doc"]
for dirpath, dirnames, filenames in os.walk(target_directory):
for filename in filenames:
if filename.endswith(tuple(target_extensions)):
file_path = os.path.join(dirpath, filename)
print(f"찾음: {file_path}")
응용 예제
- 프로젝트 내의 소스 코드(예:
.py
파일) 목록을 가져오기 - 특정 이미지 형식(예:
.jpg
나.png
)을 검색하여 일괄 처리하기 - 확장자별 파일 통계 작성하기
디렉토리 깊이 제한을 둔 탐색
os.walk
는 기본적으로 지정된 디렉토리 이하의 모든 계층을 재귀적으로 탐색하지만, 경우에 따라 특정 깊이까지만 탐색을 제한하고 싶을 수 있습니다. 이 경우 현재 깊이를 추적하고 처리 대상을 제한하여 해결할 수 있습니다.
코드 예제
다음은 디렉토리 깊이를 2로 제한하여 탐색하는 예제입니다:
import os
# 대상 디렉토리 지정
target_directory = "/path/to/your/directory"
# 최대 탐색 깊이 지정
max_depth = 2
# 깊이 제한을 둔 탐색
for dirpath, dirnames, filenames in os.walk(target_directory):
# 현재 깊이 계산
current_depth = dirpath.count(os.sep) - target_directory.count(os.sep) + 1
if current_depth > max_depth:
# 깊이를 초과하면 하위 디렉토리 탐색을 건너뜀
del dirnames[:] # dirnames를 비워 하위 디렉토리 무시
continue
print(f"깊이 {current_depth}: {dirpath}")
print(f"디렉토리: {dirnames}")
print(f"파일: {filenames}")
print("-" * 40)
출력 예제
디렉토리 구조가 아래와 같은 경우:
/path/to/your/directory
├── file1.txt
├── subdir1
│ ├── file2.txt
│ └── subsubdir1
│ └── file3.txt
└── subdir2
└── file4.txt
깊이 2까지 탐색하면 다음과 같은 출력이 나옵니다:
깊이 1: /path/to/your/directory
디렉토리: ['subdir1', 'subdir2']
파일: ['file1.txt']
----------------------------------------
깊이 2: /path/to/your/directory/subdir1
디렉토리: ['subsubdir1']
파일: ['file2.txt']
----------------------------------------
깊이 2: /path/to/your/directory/subdir2
디렉토리: []
파일: ['file4.txt']
----------------------------------------
코드 설명
os.sep
: OS 의존적인 경로 구분 기호를 가져옵니다(Windows에서는\\
, Unix에서는/
).dirpath.count(os.sep)
: 현재 디렉토리 경로에서 구분 기호의 개수를 세어 이를 기반으로 깊이를 계산합니다.del dirnames[:]
: 하위 디렉토리 목록을 비워서 그 이하의 탐색을 중단합니다.
응용 예제
- 대규모 프로젝트에서 상위 디렉토리만 탐색하고자 할 때
- 디렉토리 트리의 일부를 제한된 깊이로 표시할 때
- 디스크 작업 부담을 줄이기 위해 제한적으로 탐색할 때
숨김 파일 및 폴더 무시 방법
디렉토리 탐색을 할 때, 숨김 파일이나 폴더(보통 이름이 점.
으로 시작하는)들을 무시하고 싶을 수 있습니다. os.walk
를 사용하여 숨김 요소를 필터링함으로써 효율적인 처리가 가능합니다.
코드 예제
다음은 숨김 파일과 폴더를 무시하고 탐색하는 코드 예제입니다:
import os
# 대상 디렉토리 지정
target_directory = "/path/to/your/directory"
# 숨김 파일 및 폴더를 무시하고 탐색
for dirpath, dirnames, filenames in os.walk(target_directory):
# 숨김 폴더 무시
dirnames[:] = [d for d in dirnames if not d.startswith(".")]
# 숨김 파일 무시
visible_files = [f for f in filenames if not f.startswith(".")]
print(f"현재 경로: {dirpath}")
print(f"디렉토리: {dirnames}")
print(f"파일: {visible_files}")
print("-" * 40)
출력 예제
디렉토리 구조가 다음과 같을 경우:
/path/to/your/directory
├── file1.txt
├── .hidden_file.txt
├── subdir1
│ ├── file2.txt
│ └── .hidden_folder
│ └── file3.txt
└── subdir2
└── file4.txt
숨김 파일과 폴더를 무시하면 다음과 같은 출력이 나타납니다:
현재 경로: /path/to/your/directory
디렉토리: ['subdir1', 'subdir2']
파일: ['file1.txt']
----------------------------------------
현재 경로: /path/to/your/directory/subdir1
디렉토리: []
파일: ['file2.txt']
----------------------------------------
현재 경로: /path/to/your/directory/subdir2
디렉토리: []
파일: ['file4.txt']
----------------------------------------
코드 설명
- 숨김 폴더 무시 (
dirnames[:] = ...
):dirnames
를 덮어 씌워서 이름이.
으로 시작하는 폴더를 제외합니다. 이 작업으로 그 이하 계층도 탐색되지 않습니다. - 숨김 파일 무시 (
[f for f in filenames ...]
): 리스트 컴프리헨션을 사용하여 이름이.
으로 시작하는 파일을 제외합니다.
주의 사항
- 파일이나 폴더가 시스템 속성으로 “숨김”으로 설정된 경우(특히 Windows), 이 코드에서는 감지되지 않을 수 있습니다. 그럴 경우 추가 모듈(예:
ctypes
)을 사용해야 할 수도 있습니다.
응용 예제
- 숨김 설정이 있는 구성 파일(예:
.gitignore
나.env
)을 제외하고 처리하고자 할 때 - 사용자에게 표시할 디렉토리 목록을 생성할 때
- 대규모 데이터 세트 정리 시 숨김 요소를 제외하고 싶을 때
응용 예제: 디렉토리 크기 계산
os.walk
를 사용하여 지정된 디렉토리 내의 모든 파일 크기를 합산하고 해당 디렉토리의 총 크기를 계산할 수 있습니다. 이 방법은 특정 폴더가 얼마나 많은 저장 공간을 차지하는지 확인하려 할 때 유용합니다.
코드 예제
다음은 디렉토리 크기를 계산하는 코드 예제입니다:
import os
# 대상 디렉토리 지정
target_directory = "/path/to/your/directory"
def calculate_directory_size(directory):
total_size = 0
# 디렉토리 탐색
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
file_path = os.path.join(dirpath, filename)
try:
# 파일 크기를 가져와서 합산
total_size += os.path.getsize(file_path)
except FileNotFoundError:
# 파일이 삭제된 경우 등 예외 처리
pass
return total_size
# 디렉토리 크기 계산
directory_size = calculate_directory_size(target_directory)
# 결과 출력 (바이트 단위, MB 단위로 표시)
print(f"디렉토리 크기: {directory_size} bytes")
print(f"디렉토리 크기: {directory_size / (1024 ** 2):.2f} MB")
출력 예제
디렉토리 구조가 아래와 같은 경우:
/path/to/your/directory
├── file1.txt (500 bytes)
├── subdir1
│ ├── file2.txt (1500 bytes)
│ └── file3.txt (3000 bytes)
└── subdir2
└── file4.txt (2000 bytes)
실행 결과는 다음과 같습니다:
디렉토리 크기: 7000 bytes
디렉토리 크기: 0.01 MB
코드 설명
os.path.getsize(file_path)
: 파일 크기를 바이트 단위로 가져옵니다.- 예외 처리: 파일이 중간에 삭제된 경우나 접근 권한이 없는 경우를 대비해
FileNotFoundError
를 처리합니다. - 단위 변환: 바이트 단위 크기를 사람이 읽을 수 있는 형식(KB, MB 등)으로 변환합니다.
응용: 특정 확장자의 파일 크기 계산
특정 확장자를 가진 파일의 총합 크기를 계산하려면 아래와 같이 코드를 변경합니다:
def calculate_size_by_extension(directory, extension):
total_size = 0
for dirpath, dirnames, filenames in os.walk(directory):
for filename in filenames:
if filename.endswith(extension):
file_path = os.path.join(dirpath, filename)
try:
total_size += os.path.getsize(file_path)
except FileNotFoundError:
pass
return total_size
# 예: .txt 파일의 총합 크기 계산
txt_size = calculate_size_by_extension(target_directory, ".txt")
print(f".txt 파일 크기: {txt_size} bytes")
실용성
- 서버나 클라우드 스토리지에서 디스크 사용 상황 모니터링
- 특정 프로젝트 폴더의 리소스 소비 파악
- 디스크 공간 부족 시 청소 작업 보조
응용 예제: 전체 파일 백업 복사
os.walk
를 사용하여 디렉토리 내의 모든 파일을 재귀적으로 탐색하고 지정한 백업 위치로 복사하여 디렉토리 전체를 백업할 수 있습니다. 이 방법은 파일 구조를 유지하면서 데이터를 안전하게 복사할 때 유용합니다.
코드 예제
다음은 파일을 백업 위치로 복사하는 코드 예제입니다:
import os
import shutil
# 원본 디렉토리와 백업 위치 지정
source_directory = "/path/to/your/source_directory"
backup_directory = "/path/to/your/backup_directory"
def backup_files(source, backup):
for dirpath, dirnames, filenames in os.walk(source):
# 백업 위치 경로 계산
relative_path = os.path.relpath(dirpath, source)
backup_path = os.path.join(backup, relative_path)
# 백업 위치 디렉토리 생성
os.makedirs(backup_path, exist_ok=True)
for filename in filenames:
source_file = os.path.join(dirpath, filename)
backup_file = os.path.join(backup_path, filename)
try:
# 파일 복사
shutil.copy2(source_file, backup_file)
print(f"복사 완료: {source_file} -> {backup_file}")
except Exception as e:
print(f"복사 실패 {source_file}: {e}")
# 백업 실행
backup_files(source_directory, backup_directory)
출력 예제
디렉토리 구조가 아래와 같은 경우:
/path/to/your/source_directory
├── file1.txt
├── subdir1
│ ├── file2.txt
│ └── file3.txt
└── subdir2
└── file4.txt
백업 위치 디렉토리에 다음 구조가 생성됩니다:
/path/to/your/backup_directory
├── file1.txt
├── subdir1
│ ├── file2.txt
│ └── file3.txt
└── subdir2
└── file4.txt
코드 설명
os.makedirs(backup_path, exist_ok=True)
: 백업 위치 디렉토리를 재귀적으로 생성합니다.exist_ok=True
로 설정하여 디렉토리가 이미 있더라도 오류가 발생하지 않도록 합니다.os.path.relpath(dirpath, source)
: 원본 디렉토리로부터 상대 경로를 가져와 백업 위치 디렉토리를 구축합니다.shutil.copy2(source_file, backup_file)
: 파일의 내용뿐만 아니라 타임스탬프와 같은 메타데이터도 복사합니다.
주의 사항
- 심볼릭 링크:
shutil.copy2
는 심볼릭 링크를 일반 파일로 복사합니다. 링크를 유지하려면 별도의 처리가 필요합니다. - 디스크 용량: 백업 위치 디렉토리에 충분한 용량이 있는지 확인하세요.
- 접근 권한: 복사할 파일에 대한 접근 권한이 필요합니다.
응용 예제
- 특정 확장자만 백업:
if filename.endswith(".txt")
조건 추가. - 백업 로그 기록: 복사된 파일을 로그 파일에 기록.
- 차분 백업: 파일의 타임스탬프나 해시 값을 비교하여 변경된 파일만 복사.
요약
본 기사에서는 Python의os.walk
를 사용하여 디렉토리를 재귀적으로 탐색하는 방법과 그 응용 예제에 대해 설명했습니다. os.walk
는 파일 및 폴더를 효율적으로 탐색하고 다양한 작업을 수행하는 데 유용한 강력한 도구입니다.
기본적인 사용법부터 특정 조건에 따른 필터링, 깊이 제한, 숨김 파일 제외, 디렉토리 크기 계산 및 백업 복사 구현까지 다양한 활용 예제를 소개했습니다.
os.walk
의 유연성을 활용하면 디렉토리 작업을 자동화하고 작업 효율을 크게 향상시킬 수 있습니다. 실제 프로젝트에서 활용해 보세요!