파일 입출력(File I/O)부터 피클링(Pickling) 및 예외 처리 총정리

앞서 파이썬의 예외 처리 기법을 통해 프로그램의 안정성을 높이는 방법을 살펴보았습니다. 이번 글에서는 외부 데이터와 상호작용하는 필수 기술인 파일 입출력(File I/O)의 모든 것과, 파이썬 객체를 그대로 저장·복원하는 피클링(Pickling)의 핵심 원리를 완벽하게 파헤쳐 보겠습니다.

1. 파이썬 파일 입출력 개요 및 open() 함수

프로그램이 실행되는 동안 생성된 데이터는 메모리에만 존재하므로 프로그램이 종료되면 사라집니다. 파일 입출력을 사용하면 데이터를 영구적으로 저장하거나 외부 파일로부터 읽어올 수 있어 데이터 분석, 로그 관리, 설정 파일 처리 등에 필수적으로 활용됩니다.

파일을 제어할 때는 내장 함수 open()을 사용합니다.

open(file, mode, encoding='utf-8')
  • file: 열고자 하는 파일의 경로 및 이름

  • mode: 파일을 여는 모드 (기본값: 'r')

  • encoding: 텍스트 인코딩 방식 (한글 깨짐 방지를 위해 보통 'utf-8' 지정)

 주요 파일 모드 조합

  • r: 읽기 모드 (파일이 반드시 존재해야 함)

  • w: 쓰기 모드 (파일이 없으면 생성, 있으면 기존 내용을 덮어씀)

  • a: 추가 모드 (파일이 있으면 끝에 내용을 덧붙임, 없으면 새로 생성)

  • x: 배타적 생성 모드 (파일이 없을 때만 생성, 이미 있으면 오류 발생)

  • t / b: 텍스트 모드(t, 기본값)와 바이너리 모드(b)

2. 텍스트 파일 읽기 방법 모음

파일을 읽어올 때는 목적에 따라 다양한 메서드를 선택할 수 있습니다.

  • read(size): 파일 전체 또는 지정한 바이트/문자 수만큼 읽어 문자열로 반환합니다.

  • readline(): 파일에서 한 줄씩 읽어옵니다.

  • readlines(): 파일의 모든 줄을 각각 리스트의 요소로 담아 반환합니다.

# 1. read()를 이용한 전체 읽기
with open('example.txt', 'r', encoding='utf-8') as f:
    content = f.read()
    print(content)

# 2. 반복문을 통한 효율적인 줄 단위 읽기 (대용량 파일에 적합)
with open('example.txt', 'r', encoding='utf-8') as f:
    for line in f:
        print(line, end='')  # 줄바꿈 중복 방지를 위해 end='' 지정

3. 텍스트 파일 쓰기 및 내용 추가

파일에 데이터를 기록하려면 쓰기(w) 또는 추가(a) 모드로 파일을 열어야 합니다.

  • write(string): 문자열을 파일에 기록합니다 (w 모드는 기존 내용 덮어쓰기).

  • writelines(list): 여러 줄의 문자열이 담긴 리스트를 한 번에 파일에 씁니다.

# 여러 줄 한 번에 쓰기
lines = ["First line\n", "Second line\n", "Third line\n"]

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

# 내용 추가하기 (append 모드)
with open('example.txt', 'a', encoding='utf-8') as f:
    f.write("This line is appended.\n")

4. 안전한 리소스 관리를 위한 with 구문

파일을 열었다면 작업 완료 후 반드시 close() 메서드를 호출해 시스템 리소스를 반환해야 합니다. 하지만 이를 수동으로 처리하면 예외 발생 시 누락될 위험이 있습니다.

파이썬은 이를 방지하기 위해 with 문을 제공합니다. with 블록을 벗어나는 순간 파이썬이 자동으로 파일을 안전하게 닫아줍니다.

# 가장 권장되는 with 구문 활용 예시
with open('example.txt', 'r', encoding='utf-8') as f:
    content = f.read()
# 블록을 탈출하는 순간 파일이 자동으로 닫힘

5. 이미지 및 동영상 처리를 위한 바이너리(Binary) 모드

텍스트 파일과 달리 이미지, 오디오, 압축파일 같은 데이터는 텍스트로 해석할 수 없으므로 바이너리 모드('rb', 'wb')로 처리해야 합니다.

# 바이너리 파일 읽기 (예: 이미지)
with open('image.png', 'rb') as f:
    binary_content = f.read()
    print(binary_content[:10])  # 처음 10바이트의 원시 데이터 출력

# 바이너리 파일 쓰기
with open('output.bin', 'wb') as f:
    f.write(b'\x00\xFF\xFF')

6. os 모듈을 활용한 파일 및 경로 제어

파일 시스템과 상호작용하려면 표준 라이브러리 os 모듈을 활용합니다. 절대 경로와 상대 경로를 다루거나 파일 존재 여부를 확인할 때 매우 유용합니다.

import os

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

# 2. 파일 존재 여부 확인
print(os.path.exists('example.txt'))

# 3. 절대 경로로 변환
print(os.path.abspath('example.txt'))

7. 파일 입출력과 예외 처리의 결합

파일을 다룰 때는 “파일이 존재하지 않거나(FileNotFoundError)”, “읽기 권한이 없을 때(PermissionError)” 등 예외 상황이 빈번하게 발생합니다. 앞서 배운 예외 처리를 결합하면 프로그램의 견고함을 극대화할 수 있습니다.

ry:
    with open('example.txt', 'r', encoding='utf-8') as f:
        content = f.read()
except FileNotFoundError:
    print("오류: 파일이 존재하지 않습니다.")
except PermissionError:
    print("오류: 파일에 접근할 권한이 없습니다.")
except Exception as e:
    print(f"예기치 않은 오류가 발생했습니다: {e}")
else:
    print("파일을 성공적으로 읽었습니다.")
finally:
    print("파일 입출력 프로세스 완료.")

8. 파이썬 객체 직렬화: 피클링(Pickling)과 언피클링(Unpickling)

파이썬 프로그램에서 사용하는 복잡한 객체(리스트, 딕셔너리, 커스텀 클래스 인스턴스 등)를 파일에 그대로 저장하거나 네트워크로 전송하기 위해 바이트 스트림으로 변환하는 과정을 피클링(Pickling, 직렬화)이라고 합니다. 반대로 이를 다시 원래의 파이썬 객체로 복원하는 과정은 언피클링(Unpickling, 역직렬화)이라고 합니다.

피클링과 언피클링 사용법 (pickle 모듈)

import pickle

data = {'name': 'Alice', 'score': 95, 'items': [1, 2, 3]}

# 1. 피클링 (객체를 바이너리 파일로 저장)
with open('data.pkl', 'wb') as f:
    pickle.dump(data, f)

# 2. 언피클링 (파일에서 객체로 복원)
with open('data.pkl', 'rb') as f:
    loaded_data = pickle.load(f)

print(loaded_data)
print(type(loaded_data))  # <class 'dict'>

Pickle 사용 시 핵심 주의사항

  • 보안 위험: 피클은 파이썬 코드를 포함한 모든 객체를 직렬화할 수 있으므로, 신뢰할 수 없는 출처의 피클 파일(.pkl)을 언피클링하면 악의적 코드가 실행될 위험이 있습니다. 절대 검증되지 않은 파일을 열어서는 안 됩니다.

  • 호환성 제한: 파이썬 내부 구조에 강하게 의존하므로 타 언어와 데이터를 공유하기 어렵습니다. 언어 독립적인 교환이 필요할 때는 JSON 형식을 사용하는 것이 안전합니다.

답글 남기기