Skip to content

Python os 모듈: 파일 및 디렉토리 작업 가이드

Updated on

설정 파일을 읽거나, 출력을 저장하거나, 데이터를 정리하거나, 배포를 자동화하는 모든 Python 스크립트는 파일 시스템과 상호작용해야 합니다. 하지만 파일 경로는 Windows, macOS, Linux에서 다르게 동작합니다. 하드코딩된 /home/user/data 경로는 Windows에서 작동하지 않습니다. +/로 문자열을 수동으로 연결하면 이중 슬래시 버그와 누락된 구분자 문제가 발생합니다. 그리고 적절한 검사 없이는 스크립트가 잘못된 파일을 삭제하거나 디렉토리가 이미 존재할 때 충돌할 수 있습니다.

Python의 os 모듈은 이러한 문제를 해결합니다. 운영 체제와 작업하기 위한 이식 가능하고 크로스 플랫폼인 인터페이스를 제공합니다 -- 디렉토리 생성, 파일 나열, 환경 변수 읽기, 경로 조작, 디렉토리 트리 순회가 가능합니다. 모든 Python 설치에 포함되어 있으며, pip install이 필요 없고, 플랫폼 차이를 자동으로 처리합니다.

이 가이드는 os 모듈의 모든 필수 함수를 사용 사례별로 정리하여 프로젝트에 직접 복사할 수 있는 실용적인 예제와 함께 다룹니다.

📚

현재 작업 디렉토리 가져오기

파일로 무엇이든 하기 전에, 스크립트가 어디서 실행되고 있는지 알아야 합니다. os.getcwd()는 현재 작업 디렉토리를 절대 경로로 반환합니다.

import os
 
# 현재 작업 디렉토리 가져오기
cwd = os.getcwd()
print(cwd)  # e.g., /home/user/projects/myapp
 
# 작업 디렉토리 변경
os.chdir('/tmp')
print(os.getcwd())  # /tmp
 
# 원래 디렉토리로 돌아가기
os.chdir(cwd)

상대 경로를 구성하거나 임시로 변경한 후 작업 디렉토리를 복원해야 할 때 os.getcwd()를 사용하세요.

디렉토리 작업

디렉토리 생성

os.mkdir()는 단일 디렉토리를 생성합니다. 디렉토리가 이미 존재하면 FileExistsError를, 부모 디렉토리가 존재하지 않으면 FileNotFoundError를 발생시킵니다.

import os
 
# 단일 디렉토리 생성
os.mkdir('output')
 
# 존재하지 않는 경우에만 생성
if not os.path.exists('output'):
    os.mkdir('output')

os.makedirs()는 디렉토리를 재귀적으로 생성합니다 -- 누락된 모든 부모 디렉토리를 포함합니다. exist_ok=True 매개변수는 디렉토리가 이미 존재할 때 오류를 방지합니다.

import os
 
# 중첩된 디렉토리를 한 번의 호출로 생성
os.makedirs('data/raw/2026/january', exist_ok=True)
 
# exist_ok 없이는 'data'가 이미 존재하면 FileExistsError 발생
# os.makedirs('data/raw/2026/january')  # 오류 발생 가능

디렉토리 내용 나열

os.listdir()는 주어진 경로의 모든 항목(파일 및 디렉토리) 목록을 반환합니다.

import os
 
# 현재 디렉토리의 모든 항목 나열
entries = os.listdir('.')
print(entries)  # ['main.py', 'data', 'output', 'README.md']
 
# 특정 디렉토리의 내용 나열
data_files = os.listdir('/var/log')
print(data_files)

os.scandir()는 캐시된 파일 속성을 가진 DirEntry 객체를 반환하는 더 효율적인 대안입니다. 이름과 함께 파일 메타데이터가 필요할 때 사용하세요.

import os
 
with os.scandir('.') as entries:
    for entry in entries:
        info = entry.stat()
        print(f"{entry.name:30s}  {'DIR' if entry.is_dir() else 'FILE':4s}  {info.st_size} bytes")

디렉토리 삭제

os.rmdir()는 빈 디렉토리를 삭제합니다. 비어 있지 않은 디렉토리에는 shutil.rmtree()를 사용하세요.

import os
import shutil
 
# 빈 디렉토리 삭제
os.rmdir('output')
 
# 디렉토리와 모든 내용 삭제 (주의해서 사용)
shutil.rmtree('data/raw/2026')

파일 작업

파일 삭제

os.remove() (또는 별칭인 os.unlink())는 단일 파일을 삭제합니다. 파일이 존재하지 않으면 FileNotFoundError를 발생시킵니다.

import os
 
# 파일 삭제
os.remove('temp_output.csv')
 
# 존재 확인 후 안전한 삭제
filepath = 'temp_output.csv'
if os.path.exists(filepath):
    os.remove(filepath)
    print(f"{filepath} 삭제됨")
else:
    print(f"{filepath}을(를) 찾을 수 없음")

파일 이름 변경 및 이동

os.rename()은 파일이나 디렉토리의 이름을 변경하거나 이동합니다. 대상이 이미 존재하면 동작은 플랫폼에 따라 다릅니다 -- Unix에서는 덮어쓸 수 있지만 Windows에서는 오류가 발생할 수 있습니다. 보장된 원자적 교체에는 os.replace()를 사용하세요.

import os
 
# 파일 이름 변경
os.rename('old_report.csv', 'new_report.csv')
 
# 파일을 다른 디렉토리로 이동
os.rename('report.csv', 'archive/report_2026.csv')
 
# 원자적 교체 (모든 플랫폼에서 대상을 덮어씀)
os.replace('new_data.csv', 'data.csv')

파일 정보 가져오기

os.stat()는 크기, 권한, 타임스탬프를 포함한 상세한 파일 메타데이터를 반환합니다.

import os
from datetime import datetime
 
info = os.stat('data.csv')
print(f"크기: {info.st_size} bytes")
print(f"수정일: {datetime.fromtimestamp(info.st_mtime)}")
print(f"생성일: {datetime.fromtimestamp(info.st_ctime)}")
print(f"권한: {oct(info.st_mode)}")

os.path를 사용한 경로 작업

os.path 서브모듈은 대부분의 일상적인 파일 시스템 작업이 이루어지는 곳입니다. 플랫폼 간 경로 구성, 검증, 분해를 처리합니다.

안전하게 경로 구성

경로를 +로 연결하지 마세요. 운영 체제에 관계없이 경로를 올바르게 구성하려면 os.path.join()을 사용하세요.

import os
 
# 올바른 방법: os.path.join이 구분자를 처리
path = os.path.join('data', 'raw', 'sales.csv')
print(path)  # Unix에서 'data/raw/sales.csv', Windows에서 'data\\raw\\sales.csv'
 
# 잘못된 방법: 문자열 연결은 실패할 수 있음
bad_path = 'data' + '/' + 'raw' + '/' + 'sales.csv'  # Windows에서 실패

존재 여부 및 유형 확인

import os
 
# 경로가 존재하는지 확인 (파일 또는 디렉토리)
print(os.path.exists('/etc/hosts'))      # True (Linux/macOS에서)
 
# 파일인지 구체적으로 확인
print(os.path.isfile('main.py'))         # True
print(os.path.isfile('data'))            # False (디렉토리입니다)
 
# 디렉토리인지 구체적으로 확인
print(os.path.isdir('data'))             # True
print(os.path.isdir('main.py'))          # False

경로 분해

수동으로 문자열을 분할하지 않고 파일 경로에서 구성 요소를 추출합니다.

import os
 
filepath = '/home/user/projects/report_final.csv'
 
# 파일 이름 가져오기
print(os.path.basename(filepath))    # 'report_final.csv'
 
# 디렉토리 가져오기
print(os.path.dirname(filepath))     # '/home/user/projects'
 
# 디렉토리와 파일 이름으로 분할
directory, filename = os.path.split(filepath)
print(directory)   # '/home/user/projects'
print(filename)    # 'report_final.csv'
 
# 파일 이름과 확장자 분할
name, ext = os.path.splitext(filepath)
print(name)  # '/home/user/projects/report_final'
print(ext)   # '.csv'
 
# 상대 경로에서 절대 경로 가져오기
print(os.path.abspath('data.csv'))   # '/home/user/projects/data.csv'
 
# 사용자 홈 디렉토리 확인
print(os.path.expanduser('~/Documents'))  # '/home/user/Documents'

경로 작업 빠른 참조

함수목적출력 예시
os.path.join('a', 'b.txt')경로 구성'a/b.txt'
os.path.exists(path)경로 존재 여부True / False
os.path.isfile(path)파일인가?True / False
os.path.isdir(path)디렉토리인가?True / False
os.path.basename(path)파일 이름만'report.csv'
os.path.dirname(path)디렉토리만'/home/user'
os.path.splitext(path)이름 + 확장자 분할('report', '.csv')
os.path.abspath(path)절대 경로'/full/path/to/file'
os.path.getsize(path)파일 크기(바이트)4096
os.path.expanduser('~')홈 디렉토리'/home/user'

환경 변수

os 모듈은 시스템 환경 변수에 직접 접근을 제공합니다 -- 설정, API 키, 배포 설정을 읽는 데 필수적입니다.

import os
 
# 환경 변수 읽기 (설정되지 않으면 None 반환)
db_host = os.getenv('DATABASE_HOST')
print(db_host)
 
# 기본값으로 읽기
db_port = os.getenv('DATABASE_PORT', '5432')
print(db_port)  # DATABASE_PORT가 설정되지 않으면 '5432'
 
# os.environ 딕셔너리로 접근 (없으면 KeyError 발생)
try:
    secret = os.environ['API_SECRET']
except KeyError:
    print("API_SECRET이 설정되지 않음")
 
# 환경 변수 설정 (자식 프로세스용)
os.environ['APP_MODE'] = 'production'
 
# 모든 환경 변수 나열
for key, value in os.environ.items():
    print(f"{key}={value}")

os.getenv()os.environ[]의 차이가 중요합니다: getenv는 변수가 없을 때 None(또는 기본값)을 반환하고, os.environ[]KeyError를 발생시킵니다. 선택적 설정에는 getenv를, 부재 시 크게 실패해야 하는 필수 설정에는 os.environ을 사용하세요.

os.walk로 디렉토리 트리 순회

os.walk()는 디렉토리 트리를 재귀적으로 순회하며, 방문하는 각 디렉토리에 대해 3-튜플 (dirpath, dirnames, filenames)을 생성합니다.

import os
 
# 프로젝트 디렉토리 순회
for dirpath, dirnames, filenames in os.walk('/home/user/project'):
    # 숨겨진 디렉토리 건너뛰기
    dirnames[:] = [d for d in dirnames if not d.startswith('.')]
 
    print(f"\n디렉토리: {dirpath}")
    print(f"  하위 디렉토리: {dirnames}")
    print(f"  파일: {filenames}")

dirnames[:]의 인플레이스 수정은 os.walk가 진입하는 하위 디렉토리를 제어합니다. .git, __pycache__, node_modules 디렉토리를 건너뛰는 강력한 패턴입니다.

디렉토리 전체 크기 계산

import os
 
def get_directory_size(path):
    total = 0
    for dirpath, dirnames, filenames in os.walk(path):
        for filename in filenames:
            filepath = os.path.join(dirpath, filename)
            # 심볼릭 링크 건너뛰기
            if not os.path.islink(filepath):
                total += os.path.getsize(filepath)
    return total
 
size_bytes = get_directory_size('/home/user/project')
size_mb = size_bytes / (1024 * 1024)
print(f"전체 크기: {size_mb:.2f} MB")

일반적인 패턴

확장자로 모든 파일 찾기

import os
 
def find_files(directory, extension):
    """주어진 확장자를 가진 모든 파일을 재귀적으로 찾기."""
    matches = []
    for dirpath, dirnames, filenames in os.walk(directory):
        for filename in filenames:
            if filename.endswith(extension):
                matches.append(os.path.join(dirpath, filename))
    return matches
 
# 모든 Python 파일 찾기
python_files = find_files('/home/user/project', '.py')
for f in python_files:
    print(f)
 
# 모든 CSV 데이터 파일 찾기
csv_files = find_files('data', '.csv')
print(f"CSV 파일 {len(csv_files)}개 발견")

중첩 출력 구조 생성

import os
 
def setup_project_dirs(base_path):
    """표준 프로젝트 디렉토리 구조 생성."""
    dirs = [
        'data/raw',
        'data/processed',
        'data/output',
        'logs',
        'config',
        'reports/figures',
    ]
    for d in dirs:
        full_path = os.path.join(base_path, d)
        os.makedirs(full_path, exist_ok=True)
        print(f"생성됨: {full_path}")
 
setup_project_dirs('my_project')

임시 파일을 사용한 안전한 파일 작업

import os
import tempfile
 
# 자동 삭제되는 임시 파일 생성
with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False) as tmp:
    tmp.write('col1,col2\n1,2\n3,4\n')
    tmp_path = tmp.name
 
print(f"임시 파일: {tmp_path}")
print(f"존재: {os.path.exists(tmp_path)}")
 
# 정리
os.remove(tmp_path)

os.path vs pathlib: 어떤 것을 사용해야 할까?

Python 3.4는 os.path의 객체 지향 대안으로 pathlib를 도입했습니다. 둘 다 작동하지만 서로 다른 장점이 있습니다.

특성os.pathpathlib
스타일함수형 (문자열 기반)객체 지향
사용 가능Python 2부터Python 3.4+
경로 연결os.path.join('a', 'b')Path('a') / 'b'
존재 확인os.path.exists(p)p.exists()
파일 읽기open(os.path.join(d, f))Path(d, f).read_text()
Glob 패턴import glob; glob.glob(...)Path('.').glob('*.py')
재귀적 Globos.walk() + 필터Path('.').rglob('*.py')
파일 확장자os.path.splitext(f)[1]p.suffix
파일 줄기os.path.splitext(os.path.basename(f))[0]p.stem
크로스 플랫폼
서드파티 호환성범용대부분의 라이브러리가 Path 객체를 수용

os.path를 사용해야 할 때: 레거시 코드베이스, Python 2를 지원해야 하는 스크립트, 또는 문자열 경로만 받는 라이브러리와 작업할 때.

pathlib를 사용해야 할 때: 새 프로젝트, 더 깔끔한 구문을 원할 때, 또는 여러 경로 작업을 체이닝할 때.

# os.path 방식
import os
config_path = os.path.join(os.path.expanduser('~'), '.config', 'myapp', 'settings.json')
if os.path.isfile(config_path):
    with open(config_path) as f:
        data = f.read()
 
# pathlib 방식
from pathlib import Path
config_path = Path.home() / '.config' / 'myapp' / 'settings.json'
if config_path.is_file():
    data = config_path.read_text()

두 접근 방식 모두 유효합니다. os 모듈은 deprecated되지 않았으며 프로세스 수준 작업, 환경 변수, 저수준 시스템 호출의 표준으로 남아 있습니다. pathlib는 단순히 경로 조작을 위한 더 인체공학적인 API를 제공합니다.

크로스 플랫폼 고려사항

os 모듈은 현재 운영 체제에 자동으로 적응하지만, 알아둘 만한 세부 사항이 있습니다.

import os
 
# os.sep은 플랫폼 경로 구분자
print(os.sep)       # Unix에서 '/', Windows에서 '\\'
 
# os.linesep은 플랫폼 줄 끝 문자
print(repr(os.linesep))  # Unix에서 '\n', Windows에서 '\r\n'
 
# os.name은 OS 계열을 식별
print(os.name)      # Linux/macOS에서 'posix', Windows에서 'nt'
 
# os.path.join은 구분자를 자동으로 처리
path = os.path.join('data', 'output', 'results.csv')
# Unix에서 'data/output/results.csv'
# Windows에서 'data\\output\\results.csv'

크로스 플랫폼 스크립트의 핵심 규칙:

  • /\\로 문자열을 연결하는 대신 항상 os.path.join()을 사용하세요.
  • /home/username을 하드코딩하는 대신 os.path.expanduser('~')를 사용하세요.
  • \n을 하드코딩하는 대신 os.linesep을 사용하거나 텍스트 모드로 파일을 여세요 (줄 끝을 처리합니다).
  • 스크립트를 공유할 경우 양쪽 플랫폼에서 경로 로직을 테스트하세요.

RunCell로 파일 시스템 작업 자동화

Jupyter 노트북에서 파일 시스템 작업을 할 때 -- 데이터셋 정리, 프로젝트 구조 설정, 파일 트리 감사 -- RunCell (opens in a new tab)은 노트북 환경 위에 AI 에이전트 레이어를 추가합니다. 원하는 것을 설명하면 ("이 디렉토리 트리에서 100MB 이상의 CSV 파일을 모두 찾아 크기순으로 나열해줘") RunCell이 os 모듈 코드를 생성하고 실행하여 반복적인 파일 관리 작업을 더 빠르게 처리합니다.

FAQ

Python의 os 모듈이란 무엇인가요?

os 모듈은 Python 표준 라이브러리의 일부입니다. 파일 및 디렉토리 조작, 경로 처리, 환경 변수 접근, 프로세스 관리를 포함한 운영 체제와의 상호작용을 위한 함수를 제공합니다. import os로 가져옵니다 -- 별도 설치가 필요 없습니다.

os.path.join과 문자열 연결의 차이점은 무엇인가요?

os.path.join()은 현재 운영 체제에 맞는 올바른 경로 구분자를 자동으로 사용합니다 (Unix에서는 /, Windows에서는 \). +를 사용한 문자열 연결은 구분자를 수동으로 삽입해야 하며, 다른 플랫폼에서 코드를 실행할 때 버그로 이어집니다. 항상 os.path.join()을 사용하세요.

디렉토리의 모든 파일을 재귀적으로 나열하려면 어떻게 하나요?

os.walk()를 사용하여 디렉토리 트리를 순회하세요. 각 디렉토리에 대해 (dirpath, dirnames, filenames) 튜플을 생성합니다. os.path.join(dirpath, filename)과 결합하여 각 파일의 전체 경로를 구성하세요.

os.path와 pathlib 중 어떤 것을 사용해야 하나요?

새로운 Python 3 프로젝트에서는 pathlib가 객체 지향 API로 더 깔끔하고 읽기 쉬운 구문을 제공합니다. 하지만 osos.path는 deprecated되지 않았으며 환경 변수(os.environ), 프로세스 작업, 레거시 코드베이스에는 여전히 올바른 선택입니다. 많은 프로젝트가 둘 다 사용합니다.

Python에서 파일이나 디렉토리를 안전하게 삭제하려면 어떻게 하나요?

파일 삭제에는 os.remove(path)를, 빈 디렉토리 삭제에는 os.rmdir(path)를 사용하세요. 항상 먼저 os.path.exists(path)를 확인하거나 FileNotFoundError를 처리하기 위해 try/except 블록으로 감싸세요. 비어 있지 않은 디렉토리에는 shutil.rmtree(path)를 사용하세요.

결론

Python의 os 모듈은 스크립트가 수행하는 모든 파일 시스템 작업의 기반입니다. os.path.join()은 플랫폼 간에 안전하게 경로를 구성합니다. os.makedirs()는 한 번의 호출로 중첩된 디렉토리를 생성합니다. os.walk()는 전체 디렉토리 트리를 순회합니다. os.environos.getenv()는 시크릿을 하드코딩하지 않고 설정을 처리합니다. 그리고 os.stat()는 상세한 파일 메타데이터를 제공합니다.

경로를 많이 다루는 코드에서는 더 깔끔한 구문을 위해 ospathlib를 결합하는 것을 고려하세요. 하지만 os 모듈은 여전히 필수적입니다 -- Python에서 운영 체제와 상호작용하는 표준 방법이며, 모든 Python 개발자가 핵심 함수를 알아야 합니다.

📚