파이썬 파일 열기/읽기/쓰기 완벽 가이드 2025년

처음 파이썬으로 파일을 다뤄보려고 했을 때, ‘rb’와 ‘wb’의 차이를 몰라서 한참 헤맸던 기억이 있습니다. encoding 에러는 또 얼마나 자주 만났는지요. 실제로 파이썬 초보자의 83%가 파일 입출력에서 인코딩 문제를 겪는다는 조사 결과가 있습니다.

이 글에서는 파일 열기부터 읽기, 쓰기, 그리고 실전에서 마주치는 모든 문제의 해결법까지 7년 경력 개발자의 노하우를 모두 공개합니다.

Table of Contents

파일 열기의 기본: open() 함수 완벽 이해

가장 기본적인 파일 열기

# 파일 열기
file = open('example.txt', 'r')

# 내용 읽기
content = file.read()
print(content)

# 파일 닫기 (중요!)
file.close()

하지만 이 방식은 추천하지 않습니다. 에러가 발생하면 파일이 닫히지 않을 수 있거든요.

with문을 사용한 안전한 파일 처리

# ✅ 권장 방식
with open('example.txt', 'r', encoding='utf-8') as file:
    content = file.read()
    print(content)
# 자동으로 파일이 닫힙니다!

with문을 쓰면 에러가 발생해도 파일이 자동으로 닫힙니다. 실무에서는 100% with문을 사용하세요.

파일 모드 완벽 정리 (r, w, a, x의 모든 것)

텍스트 모드

모드의미파일 없으면기존 내용포인터 위치
‘r’읽기에러유지처음
‘w’쓰기생성삭제처음
‘a’추가생성유지
‘x’배타적 생성생성처음
‘r+’읽기+쓰기에러유지처음
‘w+’쓰기+읽기생성삭제처음
‘a+’추가+읽기생성유지

바이너리 모드

# 텍스트 모드에 'b' 추가
'rb'  # 바이너리 읽기
'wb'  # 바이너리 쓰기
'ab'  # 바이너리 추가

언제 바이너리 모드를 쓸까?

  • 이미지, 동영상, PDF 등 비텍스트 파일
  • 네트워크로 파일 전송
  • 바이트 단위 정밀 제어가 필요할 때

파일 읽기 5가지 방법 비교

1. read() – 전체 내용 한 번에

with open('data.txt', 'r', encoding='utf-8') as f:
    content = f.read()
    print(content)

장점: 간단하고 직관적

단점: 대용량 파일은 메모리 부족 발생

추천: 10MB 이하 파일

2. readline() – 한 줄씩 읽기

with open('data.txt', 'r', encoding='utf-8') as f:
    line = f.readline()
    while line:
        print(line.strip())  # 줄바꿈 제거
        line = f.readline()

장점: 메모리 효율적

단점: 코드가 길어짐

추천: 순차적 한 줄 처리

3. readlines() – 모든 줄을 리스트로

with open('data.txt', 'r', encoding='utf-8') as f:
    lines = f.readlines()
    for line in lines:
        print(line.strip())

장점: 인덱스 접근 가능

단점: 전체를 메모리에 로드

추천: 줄 수가 적은 파일

4. for문으로 순회 (가장 추천!)

with open('data.txt', 'r', encoding='utf-8') as f:
    for line in f:
        print(line.strip())

장점: 메모리 효율 + 깔끔한 코드

단점: 없음

추천: 대부분의 상황에서 최고의 선택

5. read(size) – 지정 바이트만 읽기

with open('data.txt', 'r', encoding='utf-8') as f:
    chunk = f.read(1024)  # 1KB씩 읽기
    while chunk:
        print(chunk)
        chunk = f.read(1024)

장점: 초대용량 파일 처리

단점: 줄 단위 처리 불편

추천: GB 단위 파일

파일 쓰기 실전 예제

기본 쓰기 (덮어쓰기)

# 기존 내용 삭제하고 새로 쓰기
with open('output.txt', 'w', encoding='utf-8') as f:
    f.write('첫 번째 줄\\n')
    f.write('두 번째 줄\\n')

주의: ‘w’ 모드는 기존 파일을 완전히 삭제합니다!

이어쓰기 (append)

# 기존 내용 뒤에 추가
with open('log.txt', 'a', encoding='utf-8') as f:
    f.write('새로운 로그 추가\\n')

로그 파일 기록할 때 필수입니다.

여러 줄 한 번에 쓰기

lines = ['첫 번째 줄\\n', '두 번째 줄\\n', '세 번째 줄\\n']

with open('output.txt', 'w', encoding='utf-8') as f:
    f.writelines(lines)

주의: writelines()는 자동으로 줄바꿈을 추가하지 않습니다. 직접 ‘\n’을 넣어야 합니다.

리스트를 파일로 저장

data = ['사과', '바나나', '오렌지']

with open('fruits.txt', 'w', encoding='utf-8') as f:
    for item in data:
        f.write(f"{item}\\n")

print() 함수로 파일에 쓰기

with open('output.txt', 'w', encoding='utf-8') as f:
    print('첫 번째 줄', file=f)
    print('두 번째 줄', file=f)

간단한 로그 기록할 때 편리합니다.

인코딩 문제 완벽 해결법

인코딩이란?

문자를 컴퓨터가 이해하는 숫자로 변환하는 규칙입니다. 한글은 주로 UTF-8이나 CP949를 사용합니다.

Windows에서 한글 깨짐 현상

# ❌ 깨지는 코드
with open('한글.txt', 'r') as f:
    content = f.read()
    print(content)  # 깨짐!

# ✅ 해결 방법
with open('한글.txt', 'r', encoding='utf-8') as f:
    content = f.read()
    print(content)  # 정상!

Windows 기본 인코딩은 CP949입니다. 반드시 encoding=’utf-8’을 명시하세요.

인코딩 자동 감지

# chardet 라이브러리 설치
# pip install chardet

import chardet

# 파일 인코딩 확인
with open('unknown.txt', 'rb') as f:
    raw_data = f.read()
    result = chardet.detect(raw_data)
    encoding = result['encoding']
    print(f"감지된 인코딩: {encoding}")

# 감지된 인코딩으로 읽기
with open('unknown.txt', 'r', encoding=encoding) as f:
    content = f.read()
    print(content)

출처를 모르는 파일 처리할 때 생명줄입니다.

인코딩 에러 무시하기

# 에러 발생하는 문자 건너뛰기
with open('problematic.txt', 'r', encoding='utf-8', errors='ignore') as f:
    content = f.read()

# 에러 발생 시 ? 로 대체
with open('problematic.txt', 'r', encoding='utf-8', errors='replace') as f:
    content = f.read()

완벽한 해결은 아니지만 급할 때 유용합니다.

경로 문제 해결하기

절대 경로 vs 상대 경로

# 절대 경로 (전체 경로)
file = open('C:/Users/username/documents/data.txt', 'r')

# 상대 경로 (현재 디렉토리 기준)
file = open('data.txt', 'r')
file = open('./data/data.txt', 'r')
file = open('../data.txt', 'r')  # 상위 디렉토리

pathlib로 경로 다루기 (추천!)

from pathlib import Path

# 현재 디렉토리
current = Path.cwd()
print(current)

# 파일 경로 생성
file_path = Path('data') / 'users' / 'info.txt'

# 파일 존재 확인
if file_path.exists():
    with open(file_path, 'r', encoding='utf-8') as f:
        content = f.read()

pathlib는 OS에 상관없이 경로를 안전하게 처리합니다.

파일 존재 여부 확인

import os

# 방법 1: os.path
if os.path.exists('data.txt'):
    print('파일이 존재합니다')

# 방법 2: pathlib
from pathlib import Path
if Path('data.txt').exists():
    print('파일이 존재합니다')

# 방법 3: try-except
try:
    with open('data.txt', 'r') as f:
        content = f.read()
except FileNotFoundError:
    print('파일이 없습니다')

CSV 파일 다루기

기본 CSV 읽기

import csv

with open('data.csv', 'r', encoding='utf-8') as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)  # 리스트로 반환

헤더가 있는 CSV 읽기

import csv

with open('users.csv', 'r', encoding='utf-8') as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row['name'], row['age'])  # 딕셔너리로 접근

DictReader가 훨씬 직관적입니다.

CSV 파일 쓰기

import csv

data = [
    ['이름', '나이', '직업'],
    ['홍길동', 30, '개발자'],
    ['김철수', 25, '디자이너']
]

with open('output.csv', 'w', newline='', encoding='utf-8-sig') as f:
    writer = csv.writer(f)
    writer.writerows(data)

주의:

  • newline=”을 빼면 빈 줄이 생깁니다
  • utf-8-sig를 쓰면 엑셀에서 한글이 안 깨집니다

pandas로 CSV 다루기 (추천!)

import pandas as pd

# CSV 읽기
df = pd.read_csv('data.csv', encoding='utf-8')
print(df.head())

# CSV 쓰기
df.to_csv('output.csv', index=False, encoding='utf-8-sig')

대량 데이터는 pandas가 압도적으로 편합니다.

JSON 파일 처리하기

JSON 파일 읽기

import json

with open('data.json', 'r', encoding='utf-8') as f:
    data = json.load(f)
    print(data['name'])

JSON 파일 쓰기

import json

data = {
    'name': '홍길동',
    'age': 30,
    'skills': ['Python', 'JavaScript']
}

with open('output.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

옵션 설명:

  • ensure_ascii=False: 한글을 그대로 저장
  • indent=2: 들여쓰기로 예쁘게 포맷팅

JSON 문자열 다루기

import json

# 딕셔너리 → JSON 문자열
data = {'name': '홍길동', 'age': 30}
json_str = json.dumps(data, ensure_ascii=False)

# JSON 문자열 → 딕셔너리
data = json.loads(json_str)

API 응답 처리할 때 자주 씁니다.

바이너리 파일 처리 (이미지, PDF 등)

이미지 파일 읽기

# 이미지를 바이너리로 읽기
with open('photo.jpg', 'rb') as f:
    image_data = f.read()
    print(f"파일 크기: {len(image_data)} bytes")

이미지 파일 복사하기

# 바이너리 복사
with open('original.jpg', 'rb') as f:
    data = f.read()

with open('copy.jpg', 'wb') as f:
    f.write(data)

Pillow로 이미지 처리

from PIL import Image

# 이미지 열기
img = Image.open('photo.jpg')

# 크기 조정
img_resized = img.resize((800, 600))

# 저장
img_resized.save('resized.jpg')

대용량 파일 처리 전략

청크 단위로 읽기

def read_large_file(file_path, chunk_size=1024*1024):  # 1MB씩
    with open(file_path, 'rb') as f:
        while True:
            chunk = f.read(chunk_size)
            if not chunk:
                break
            # 청크 처리
            process_chunk(chunk)

제너레이터로 메모리 효율화

def read_lines_generator(file_path):
    with open(file_path, 'r', encoding='utf-8') as f:
        for line in f:
            yield line.strip()

# 사용
for line in read_lines_generator('huge_file.txt'):
    print(line)

10GB 파일도 문제없이 처리됩니다.

진행률 표시하기

from tqdm import tqdm

with open('large.txt', 'r', encoding='utf-8') as f:
    lines = f.readlines()
    for line in tqdm(lines, desc='처리 중'):
        # 처리
        process_line(line)

실전 프로젝트: 로그 분석기

from collections import Counter
from datetime import datetime

def analyze_log_file(log_path):
    error_count = 0
    warning_count = 0
    ip_addresses = []

    with open(log_path, 'r', encoding='utf-8') as f:
        for line in f:
            if 'ERROR' in line:
                error_count += 1
            elif 'WARNING' in line:
                warning_count += 1

            # IP 주소 추출 (간단한 예제)
            parts = line.split()
            if len(parts) > 0 and '.' in parts[0]:
                ip_addresses.append(parts[0])

    # 결과 저장
    report = f"""
로그 분석 보고서
생성 시간: {datetime.now()}
총 라인 수: {error_count + warning_count}
에러 수: {error_count}
경고 수: {warning_count}

상위 5개 IP:
"""

    for ip, count in Counter(ip_addresses).most_common(5):
        report += f"{ip}: {count}회\\n"

    with open('log_report.txt', 'w', encoding='utf-8') as f:
        f.write(report)

    print("분석 완료! log_report.txt 확인하세요.")

# 사용
# analyze_log_file('server.log')

파일 입출력 자주 하는 실수 TOP 10

1. 파일을 닫지 않음

# ❌ 나쁜 예
f = open('data.txt', 'r')
content = f.read()
# f.close() 없음!

# ✅ 좋은 예
with open('data.txt', 'r') as f:
    content = f.read()

2. 인코딩 지정 안 함

# ❌ Windows에서 에러
with open('한글.txt', 'r') as f:
    content = f.read()

# ✅ 항상 인코딩 명시
with open('한글.txt', 'r', encoding='utf-8') as f:
    content = f.read()

3. 경로 문제

# ❌ 백슬래시 하나만
path = 'C:\\new\\data.txt'  # \\n이 줄바꿈으로!

# ✅ 해결 방법
path = 'C:/new/data.txt'  # 슬래시
path = r'C:\\new\\data.txt'  # raw 문자열
path = 'C:\\\\new\\\\data.txt'  # 이스케이프

4. 파일 존재 확인 안 함

# ❌ 에러 발생
with open('data.txt', 'r') as f:
    content = f.read()

# ✅ 확인 후 처리
from pathlib import Path
if Path('data.txt').exists():
    with open('data.txt', 'r') as f:
        content = f.read()
else:
    print('파일이 없습니다')

5. 모드 선택 실수

# ❌ 읽기 모드로 쓰기 시도
with open('data.txt', 'r') as f:
    f.write('내용')  # 에러!

# ✅ 올바른 모드
with open('data.txt', 'w') as f:
    f.write('내용')

6. 대용량 파일을 한 번에 읽음

# ❌ 메모리 부족
with open('10gb.txt', 'r') as f:
    content = f.read()  # 메모리 폭발!

# ✅ 한 줄씩 처리
with open('10gb.txt', 'r') as f:
    for line in f:
        process(line)

7. CSV에서 newline 빠뜨림

# ❌ 빈 줄 생김
with open('data.csv', 'w') as f:
    writer = csv.writer(f)

# ✅ newline 추가
with open('data.csv', 'w', newline='') as f:
    writer = csv.writer(f)

8. JSON 한글 깨짐

# ❌ 한글이 유니코드로
json.dump(data, f)

# ✅ ensure_ascii=False
json.dump(data, f, ensure_ascii=False)

9. 상대 경로 오해

# 현재 디렉토리 확인
import os
print(os.getcwd())  # 현재 작업 디렉토리

# 스크립트 위치 기준으로
import os
script_dir = os.path.dirname(__file__)
file_path = os.path.join(script_dir, 'data.txt')

10. 바이너리 파일을 텍스트 모드로

# ❌ 이미지를 텍스트로
with open('photo.jpg', 'r') as f:
    data = f.read()  # 에러!

# ✅ 바이너리 모드
with open('photo.jpg', 'rb') as f:
    data = f.read()

고급 팁: 컨텍스트 매니저 만들기

class FileManager:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
        self.file = None

    def __enter__(self):
        self.file = open(self.filename, self.mode, encoding='utf-8')
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.file:
            self.file.close()

# 사용
with FileManager('data.txt', 'r') as f:
    content = f.read()

체크리스트: 파일 처리 전 필수 확인

✅ with문 사용하기

✅ encoding=’utf-8′ 명시

✅ 파일 존재 여부 확인

✅ 올바른 모드 선택 (r/w/a)

✅ 대용량 파일은 청크 단위 처리

✅ 경로 문제 확인 (절대/상대)

✅ CSV는 newline=” 추가

✅ JSON은 ensure_ascii=False

✅ 에러 핸들링 추가

마치며: 파일 입출력 마스터의 길

파일 입출력은 파이썬 기초 중의 기초지만, 제대로 다루려면 많은 것을 알아야 합니다. 인코딩, 경로, 모드 선택 등 처음엔 복잡해 보이지만, 이 가이드의 패턴들을 익히면 어떤 파일도 자신 있게 다룰 수 있습니다.

핵심만 기억하세요:

  1. 항상 with문 사용
  2. encoding=’utf-8′ 명시
  3. 대용량은 한 줄씩

이 세 가지만 지켜도 90%의 문제가 해결됩니다!

이 글이 도움되셨다면 북마크하고, 파일 처리로 고민하는 동료에게 공유해주세요!


참고 자료

댓글 남기기