파이썬(Python) 공부 8편
파일 입출력 완전 정복
실무에서 파이썬을 쓰다 보면 파일을 읽고 쓰는 작업이 반드시 필요합니다. 텍스트 파일 처리부터 업무 자동화에 필수인 CSV, API 통신에 쓰이는 JSON까지 파이썬 파일 입출력의 모든 것을 정리합니다.
📁 open() — 파일 열기의 모든 것
파이썬에서 파일을 다루려면 먼저 open() 함수로 파일을 열어야 합니다. open(파일경로, 모드, encoding='utf-8') 형태로 사용하며, 사용 후 반드시 close()로 닫아야 합니다. (with문을 쓰면 자동으로 처리됩니다)
| 모드 | 의미 | 파일 없을 때 | 기존 내용 | 읽기 | 쓰기 |
|---|---|---|---|---|---|
| r | 읽기 (기본값) | FileNotFoundError | 유지 | O | X |
| w | 쓰기 (덮어씀) | 새로 생성 | 삭제 | X | O |
| a | 추가 (append) | 새로 생성 | 유지·추가 | X | O |
| x | 배타적 생성 | 새로 생성 | — | X | O (이미 있으면 오류) |
| r+ | 읽기+쓰기 | FileNotFoundError | 유지 | O | O |
| rb / wb | 바이너리 읽기/쓰기 | — | — | 이미지·PDF 등 바이너리 파일 | |
✅ with문 — 파일을 안전하게 처리하는 방법
컨텍스트 매니저(Context Manager)라고 불리는 with문은 블록이 끝나면 자동으로 close()를 호출합니다. 수동으로 close()를 호출하는 방법보다 안전하고 코드가 간결합니다.
# ❌ 수동 방식 — 예외 발생 시 close()가 실행 안 될 수 있음 f = open("data.txt", "r", encoding="utf-8") content = f.read() f.close() # 직접 닫아야 함 # ✅ with문 — 블록 종료 시 자동 close() 호출 with open("data.txt", "r", encoding="utf-8") as f: content = f.read() # with 블록을 벗어나면 f.close() 자동 실행 # 파일 두 개 동시에 열기 with open("input.txt", "r", encoding="utf-8") as fin, \ open("output.txt", "w", encoding="utf-8") as fout: fout.write(fin.read())
📖 파일 읽기 — read / readline / readlines
# sample.txt 내용: # 첫 번째 줄 # 두 번째 줄 # 세 번째 줄 # ① read() — 파일 전체를 하나의 문자열로 with open("sample.txt", "r", encoding="utf-8") as f: content = f.read() print(content) # 파일 전체 출력 # ② readline() — 한 줄씩 읽기 with open("sample.txt", "r", encoding="utf-8") as f: line1 = f.readline() # "첫 번째 줄\n" line2 = f.readline() # "두 번째 줄\n" print(line1.strip()) # 줄바꿈 제거 → "첫 번째 줄" # ③ readlines() — 모든 줄을 리스트로 with open("sample.txt", "r", encoding="utf-8") as f: lines = f.readlines() print(lines) # ['첫 번째 줄\n', '두 번째 줄\n', '세 번째 줄'] # ④ for문으로 줄씩 순회 — 가장 메모리 효율적 (권장) with open("sample.txt", "r", encoding="utf-8") as f: for line in f: print(line.strip()) # 한 줄씩 처리 (대용량 파일에 적합)
✏ 파일 쓰기 — write / writelines / append
# ① write() — 문자열 쓰기 (모드 'w' → 기존 내용 삭제 후 새로 작성) with open("output.txt", "w", encoding="utf-8") as f: f.write("첫 번째 줄\n") f.write("두 번째 줄\n") print(f.write("세 번째 줄\n")) # write()는 쓴 문자 수 반환 # ② writelines() — 리스트를 한 번에 씀 (줄바꿈 자동 없음 → 직접 포함) lines = ["Python\n", "is\n", "fun\n"] with open("output.txt", "w", encoding="utf-8") as f: f.writelines(lines) # ③ append 모드 'a' — 기존 내용 뒤에 추가 with open("log.txt", "a", encoding="utf-8") as f: f.write("2026-03-31 로그 항목 추가\n") # ④ print()로 파일에 쓰기 — file 인수 활용 with open("result.txt", "w", encoding="utf-8") as f: for i in range(1, 6): print(f"항목 {i}: {i ** 2}", file=f) # 줄바꿈 자동 포함
- 기존 파일에 내용을 추가하려면 반드시 'a' 모드 사용
- 파일 존재 여부를 먼저 확인하려면 os.path.exists() 또는 pathlib의 Path.exists() 활용
📊 CSV 파일 처리 — csv 모듈
CSV(Comma-Separated Values)는 데이터를 쉼표로 구분한 텍스트 파일 형식입니다. 엑셀·스프레드시트와 호환되며 데이터 처리에 자주 사용됩니다. 파이썬 내장 csv 모듈을 사용하면 됩니다.
import csv # ① CSV 쓰기 — csv.writer data = [ ["이름", "나이", "도시"], # 헤더 ["Alice", 25, "서울"], ["Bob", 30, "부산"], ["Carol", 28, "대구"], ] with open("users.csv", "w", encoding="utf-8-sig", newline="") as f: writer = csv.writer(f) writer.writerows(data) # 여러 행 한 번에 # ② CSV 읽기 — csv.reader with open("users.csv", "r", encoding="utf-8-sig") as f: reader = csv.reader(f) for row in reader: print(row) # ['이름', '나이', '도시'] ... # ③ DictReader — 헤더를 키로 사용 (더 편리) with open("users.csv", "r", encoding="utf-8-sig") as f: reader = csv.DictReader(f) for row in reader: print(f"{row['이름']}, {row['나이']}세, {row['도시']}") # Alice, 25세, 서울 ... # ④ DictWriter — 딕셔너리로 쓰기 users = [ {"이름": "Dave", "나이": 22, "도시": "인천"}, ] with open("new_users.csv", "w", encoding="utf-8-sig", newline="") as f: fieldnames = ["이름", "나이", "도시"] writer = csv.DictWriter(f, fieldnames=fieldnames) writer.writeheader() # 헤더 행 작성 writer.writerows(users)
- 엑셀에서 열 때 한글이 깨지지 않으려면 encoding='utf-8-sig' 사용 (BOM 포함 UTF-8)
- Python 내부에서만 처리할 때는 encoding='utf-8'으로 충분
- CSV 쓰기 시 newline='' 설정 → 줄바꿈 이중 삽입 방지
🌐 JSON 파일 처리 — json 모듈
JSON(JavaScript Object Notation)은 데이터 교환의 표준 형식으로, API 통신·설정 파일·로그 저장에 널리 쓰입니다. 파이썬 딕셔너리/리스트와 구조가 유사해 변환이 직관적입니다.
- json.load(f): 파일 → 파이썬 객체 (딕셔너리/리스트)
- json.dump(obj, f): 파이썬 객체 → 파일
- json.loads(str): JSON 문자열 → 파이썬 객체
- json.dumps(obj): 파이썬 객체 → JSON 문자열
import json data = { "name": "Alice", "age": 25, "skills": ["Python", "SQL"], "active": True, } # ① dump() — 파이썬 객체 → JSON 파일 with open("user.json", "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) # ensure_ascii=False → 한글 유지 / indent=2 → 보기 좋게 들여쓰기 # ② load() — JSON 파일 → 파이썬 객체 with open("user.json", "r", encoding="utf-8") as f: loaded = json.load(f) print(loaded["name"]) # Alice print(type(loaded)) # <class 'dict'> # ③ dumps() — 파이썬 객체 → JSON 문자열 (API 응답, 로그 출력 등) json_str = json.dumps(data, ensure_ascii=False, indent=2) print(json_str) print(type(json_str)) # <class 'str'> # ④ loads() — JSON 문자열 → 파이썬 객체 (API 응답 파싱) api_response = '{"status": 200, "message": "OK"}' parsed = json.loads(api_response) print(parsed["status"]) # 200 # JSON ↔ 파이썬 타입 대응 # JSON object → dict / JSON array → list # JSON string → str / JSON number → int/float # JSON true → True / JSON false → False # JSON null → None
📁 pathlib — 현대적인 파일 경로 처리
파이썬 3.4+에서 추가된 pathlib은 파일 경로를 객체로 다루는 현대적인 방법입니다. 문자열로 경로를 다루는 os.path보다 직관적이고 사용하기 편합니다.
from pathlib import Path # 경로 생성 p = Path("data/users.csv") home = Path.home() # 홈 디렉토리 cwd = Path.cwd() # 현재 작업 디렉토리 # / 연산자로 경로 조합 (OS 무관 동작) log_path = Path("logs") / "2026" / "app.log" print(log_path) # logs/2026/app.log # 경로 정보 조회 print(p.name) # users.csv (파일명) print(p.stem) # users (확장자 제외) print(p.suffix) # .csv (확장자) print(p.parent) # data (상위 디렉토리) # 존재 여부 · 종류 확인 print(p.exists()) # True / False print(p.is_file()) # 파일인가 print(p.is_dir()) # 디렉토리인가 # 디렉토리 생성 Path("output/reports").mkdir(parents=True, exist_ok=True) # parents=True → 중간 폴더도 생성 / exist_ok=True → 이미 있어도 오류 없음 # 파일 목록 조회 for f in Path(".").glob("*.txt"): # 현재 폴더의 .txt 파일 print(f.name) for f in Path(".").rglob("*.py"): # 하위 폴더까지 재귀적으로 print(f) # pathlib로 파일 읽기/쓰기 (open() 없이도 가능) text = Path("data.txt").read_text(encoding="utf-8") Path("output.txt").write_text("Hello!", encoding="utf-8")
📝 8편 실습 문제
- 학생 이름·국어·영어·수학 점수가 담긴 CSV 파일 생성하기
- 생성한 CSV를 읽어 총점·평균을 계산하고 결과를 새 CSV로 저장하기
- 앱 설정(이름·버전·디버그 여부·허용IP목록)을 담은 config.json 생성
- 파일을 읽어 디버그 모드를 토글(True↔False)하고 다시 저장
import csv, json # 실습 1 — 성적 CSV 처리 scores = [ ["이름", "국어", "영어", "수학"], ["Alice", 90, 85, 92], ["Bob", 78, 88, 70], ["Carol", 95, 91, 89], ] with open("scores.csv", "w", encoding="utf-8-sig", newline="") as f: csv.writer(f).writerows(scores) # 읽어서 총점·평균 계산 후 저장 results = [] with open("scores.csv", "r", encoding="utf-8-sig") as f: for i, row in enumerate(csv.reader(f)): if i == 0: results.append(row + ["총점", "평균"]) else: s = [int(x) for x in row[1:]] results.append(row + [sum(s), f"{sum(s)/len(s):.1f}"]) with open("scores_result.csv", "w", encoding="utf-8-sig", newline="") as f: csv.writer(f).writerows(results) # 실습 2 — JSON 설정 파일 토글 config = {"app": "MyApp", "version": "1.0", "debug": False, "allowed_ips": ["127.0.0.1"]} with open("config.json", "w", encoding="utf-8") as f: json.dump(config, f, ensure_ascii=False, indent=2) with open("config.json", "r", encoding="utf-8") as f: cfg = json.load(f) cfg["debug"] = not cfg["debug"] # 토글 with open("config.json", "w", encoding="utf-8") as f: json.dump(cfg, f, ensure_ascii=False, indent=2) print(f"debug 모드: {cfg['debug']}") # debug 모드: True
- open() 모드: r(읽기) w(쓰기·덮어씀) a(추가) x(새 파일만) b(바이너리)
- with문: 블록 종료 시 자동 close() / 파일 처리 표준 패턴 / encoding='utf-8' 항상 명시
- 읽기: read()(전체) / readline()(한 줄) / readlines()(리스트) / for line in f(대용량 권장)
- 쓰기: write(str) / writelines(list) / print(..., file=f)
- CSV: csv.reader/writer / DictReader/DictWriter / 엑셀 한글은 utf-8-sig
- JSON: load/dump(파일) / loads/dumps(문자열) / ensure_ascii=False(한글 유지) / indent=2(들여쓰기)
- pathlib: Path()로 경로 객체 생성 / /로 경로 조합 / exists() glob() mkdir() 등 편리한 메서드
try/except/else/finally / 예외 종류 / raise / 사용자 정의 예외