C
Python/파일/Lesson 23

파일 입출력

45분·theory
이 챕터
1/2
Python

파일 입출력

🎯 이 lesson 을 읽고 나면

이 lesson 을 다 읽고 나면 아래 3가지를 자신 있게 할 수 있습니다.

  • ✅ pathlib.Path 가 os.path 의 모던 대체
  • ✅ with open() 컨텍스트 매니저 + 인코딩 명시
  • ✅ csv · json · yaml 표준 모듈 사용

학습 목표를 체크리스트로 두고 다 답할 수 있게 되면 lesson 을 닫으세요.

파일 I/O 6가지 — 코드 + 실행 결과

파일 읽기·쓰기 = 데이터를 디스크에 저장하거나 불러오기. 모든 프로그램의 기본.


1. 텍스트 파일 쓰기

python
# 파일 새로 만들고 쓰기
with open("memo.txt", "w", encoding="utf-8") as f:
    f.write("안녕하세요
")
    f.write("두 번째 줄")

# 파일 자동 close — with 문 핵심

"w" = write (덮어쓰기). 기존 내용 사라짐. "a" = append (이어쓰기).

⚠️ 한국어는 encoding="utf-8" 필수. 안 쓰면 Windows 에서 깨짐.


2. 텍스트 파일 읽기

python
# 한 번에 다 읽기
with open("memo.txt", "r", encoding="utf-8") as f:
    내용 = f.read()
print(내용)

# 한 줄씩 (큰 파일 메모리 절약)
with open("memo.txt", "r", encoding="utf-8") as f:
    for 줄 in f:
        print(줄.rstrip())     # 줄 끝의 
 제거

# 모든 줄을 list 로
with open("memo.txt", "r", encoding="utf-8") as f:
    줄들 = f.readlines()
print(줄들)

3. with 문 — 자동 close

python
# ❌ 옛날 방식 — close() 잊으면 메모리 누수
f = open("memo.txt", "r", encoding="utf-8")
내용 = f.read()
f.close()                     # 잊기 쉬움

# ✅ 모던 방식 — with 가 자동 close
with open("memo.txt", "r", encoding="utf-8") as f:
    내용 = f.read()
# 블록 끝나면 f.close() 자동 호출 (예외 발생해도)

with 는 Python 의 자원 관리 표준. 항상 사용.


4. JSON 읽기·쓰기

python
import json

# Python dict → JSON 파일
데이터 = {"이름": "홍길동", "나이": 28, "취미": ["독서", "코딩"]}
with open("user.json", "w", encoding="utf-8") as f:
    json.dump(데이터, f, ensure_ascii=False, indent=2)

# JSON 파일 → Python dict
with open("user.json", "r", encoding="utf-8") as f:
    불러옴 = json.load(f)
print(불러옴["이름"])         # 홍길동

ensure_ascii=False — 한국어 그대로 저장 (없으면 \uXXXX 인코딩).
indent=2 — 사람이 보기 좋게 들여쓰기.


5. CSV 읽기·쓰기

python
import csv

# 쓰기
학생들 = [
    ["이름", "나이", "점수"],
    ["홍길동", 28, 85],
    ["이몽룡", 30, 92],
]
with open("학생.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.writer(f)
    writer.writerows(학생들)

# 읽기
with open("학생.csv", "r", encoding="utf-8") as f:
    reader = csv.reader(f)
    for 행 in reader:
        print(행)
# ['이름', '나이', '점수']
# ['홍길동', '28', '85']     ← 모두 문자열로 읽힘
# ['이몽룡', '30', '92']

⚠️ newline="" — Windows 의 빈 줄 문제 회피.


6. pathlib — 모던 경로 처리 (Python 3.6+)

python
from pathlib import Path

# 경로 생성 — OS 무관 (Windows / Mac / Linux)
경로 = Path("data") / "user.json"
print(경로)                   # data\user.json (Win) or data/user.json (Mac)

# 파일 존재?
if 경로.exists():
    내용 = 경로.read_text(encoding="utf-8")

# 한 줄로 쓰기
Path("hello.txt").write_text("안녕!", encoding="utf-8")

# 폴더 생성 (이미 있으면 OK)
Path("data").mkdir(exist_ok=True)

os.path.join 옛 방식 — pathlib 이 모던 권장.


한 줄 요약

작업코드
쓰기with open(f, "w", encoding="utf-8") as f: f.write(s)
읽기with open(f, "r", encoding="utf-8") as f: s = f.read()
JSONjson.dump(data, f) / json.load(f)
CSVcsv.writer(f) / csv.reader(f)
경로Path("dir") / "file.txt"

핵심: with + encoding="utf-8" 항상. 없으면 한국어 깨지거나 close 잊음.

💻 나쁜 예시 — os.path + 수동 close
import os

# os.path — 가독성 낮음
base = '/data'
filepath = os.path.join(base, 'users', 'data.csv')  # 길고 번거로움

# encoding 미지정, 수동 close
f = open(filepath)  # 플랫폼 기본 인코딩 (위험)
try:
    content = f.read()
finally:
    f.close()  # with 없이 직접 관리
💻 좋은 예시 — pathlib + with 문 + csv/json
from pathlib import Path
import csv
import json
from typing import Generator

# pathlib — 현대적 경로 처리
base = Path('/data')
filepath = base / 'users' / 'data.csv'  # / 연산자로 결합

print(filepath.name)        # 'data.csv'
print(filepath.stem)        # 'data'
print(filepath.suffix)      # '.csv'
print(filepath.parent)      # /data/users
print(filepath.exists())    # True/False

# 디렉토리 생성
output_dir = Path('output') / 'reports'
output_dir.mkdir(parents=True, exist_ok=True)  # 중간 경로도 생성

# 텍스트 파일 읽기/쓰기
config_path = Path('config.json')

if config_path.exists():
    text = config_path.read_text(encoding='utf-8')  # 한 줄로 읽기
config_path.write_text('{"key": "value"}', encoding='utf-8')  # 한 줄로 쓰기

# 대용량 파일 스트리밍 처리
def process_large_log(filepath: Path) -> Generator[dict, None, None]:
    """대용량 로그 파일 라인별 스트리밍 — 메모리 O(1)"""
    with open(filepath, encoding='utf-8', errors='replace') as f:
        for line in f:  # 라인별 읽기 (전체 로드 안 함)
            line = line.strip()
            if line and not line.startswith('#'):
                yield {'raw': line, 'length': len(line)}

# CSV 처리
def read_users_csv(filepath: Path) -> list[dict]:
    with open(filepath, encoding='utf-8', newline='') as f:
        reader = csv.DictReader(f)
        return list(reader)

def write_users_csv(filepath: Path, users: list[dict]) -> None:
    with open(filepath, 'w', encoding='utf-8', newline='') as f:
        if users:
            writer = csv.DictWriter(f, fieldnames=users[0].keys())
            writer.writeheader()
            writer.writerows(users)

# JSON 처리
def load_config(filepath: Path) -> dict:
    with open(filepath, encoding='utf-8') as f:
        return json.load(f)

def save_config(filepath: Path, config: dict) -> None:
    with open(filepath, 'w', encoding='utf-8') as f:
        json.dump(config, f, ensure_ascii=False, indent=2)

# glob으로 파일 검색
for csv_file in Path('data').glob('**/*.csv'):  # 재귀 검색
    print(csv_file)

🐍 실행해보기 — 파일 입출력

위 개념을 실제로 코드로 실행해보세요. 값을 바꿔가며 어떻게 동작하는지 직접 확인하는 게 가장 빠른 학습.
✏️ Python 코드
📟 콘솔 출력
▶ 실행 버튼을 눌러보세요
🐍 Pyodide로 실제 Python 실행 — 첫 실행 시 로딩 3~5초 소요

🤖 AI 에게 이렇게 요청해보세요

이 lesson 의 개념을 알면 AI 에게 구체적으로 지시할 수 있습니다. 막연한 "고쳐줘" 가 아니라 어휘를 가진 요청 — 그게 토큰 절약의 출발점입니다.

  • "이 os.path 코드를 pathlib 로 마이그레이션해줘"
  • "이 with open 블록에 적절한 인코딩 (encoding='utf-8') 명시해줘"

왜 이게 토큰을 줄이나

개념을 모를 땐 AI 답변을 받고도 "그게 뭐예요?" 를 다시 물어야 합니다. 그 "다시 물음" 이 토큰을 잡아먹습니다. 개념 한 번 익혀두면 대화가 한 번에 끝납니다.

먼저 읽으면 좋은 개념: pytest 입문
파일 입출력 - Python