Menu

파이썬 파일 입출력: 읽기, 쓰기, 추가 완벽 정리

파이썬에서 파일을 안전하게 다루는 법 - with문 사용법부터 텍스트/바이너리 모드, pathlib까지 실전 위주로 정리했습니다.

파일은 결국 경로가 붙은 문자열일 뿐이다

대부분의 프로그램은 언젠가 파일을 읽거나 써야 할 일이 생깁니다. 설정 파일, 사용자 데이터, 로그, CSV 내보내기, 작은 캐시 같은 것들이죠. 파이썬에서는 이 작업이 아주 간단합니다. 내장 함수 open() 하나와, 파일을 확실히 닫아주는 with 블록만 있으면 끝입니다.

자주 쓰이는 경우들을 하나씩 살펴보겠습니다.

파일 전체 읽기

가장 간단한 읽기 방법입니다:

with open("notes.txt") as f:
    contents = f.read()

print(contents)

open("notes.txt")은 파일을 읽기 모드로 여는 겁니다(기본값이 읽기 모드예요). with 블록을 쓰면 블록을 벗어날 때 파이썬이 알아서 파일을 닫아줍니다 — 중간에 예외가 터져도요. 한 번 닫히면 f는 더 이상 쓸 수 없고, 텍스트는 contents 안에 들어 있습니다.

contents는 파일 전체 내용이 담긴 하나의 문자열입니다. 작은 파일이면 괜찮지만, 2GB짜리 로그 파일이라면 얘기가 달라지죠.

한 줄씩 파일 읽기

파일이 크다면 전체를 메모리에 올리지 말고, 이렇게 순회하면서 읽는 게 좋습니다:

with open("big.log") as f:
    for line in f:
        if "ERROR" in line:
            print(line.strip())

반복할 때마다 줄 끝의 개행 문자까지 포함해서 한 줄씩 넘어옵니다. .strip()이 자주 등장하는 이유가 바로 이 때문이죠. 줄 단위 리스트가 필요하다면 f.readlines()를 쓰면 되지만, 대부분은 그냥 파일 객체를 바로 순회하는 방식이 낫습니다.

파일 쓰기

파일에 쓰려면 두 번째 인자로 모드를 넘겨주면 됩니다:

with open("output.txt", "w") as f:
    f.write("first line\n")
    f.write("second line\n")

몇 가지 주의할 점이 있습니다:

  • "w"는 덮어쓰기 모드입니다. output.txt가 이미 존재한다면, open이 실행되는 순간 기존 내용은 사라집니다.
  • 줄바꿈은 직접 넣어줘야 합니다. f.write("hello")는 딱 다섯 글자만 기록하고, 끝에 개행 문자를 붙여주지 않습니다.

덮어쓰지 않고 뒤에 이어서 쓰고 싶다면:

with open("output.txt", "a") as f:
    f.write("another line\n")

writelines를 활용하면 여러 줄을 한 번에 써넣을 수도 있어요:

lines = ["a\n", "b\n", "c\n"]
with open("letters.txt", "w") as f:
    f.writelines(lines)

파일에 print로 출력하기

print 함수에는 file 인자가 있어서, 개행 문자를 일일이 붙이지 않고도 파일에 간편하게 쓸 수 있습니다:

with open("log.txt", "w") as f:
    print("started", file=f)
    print("finished", file=f)

print는 인자들을 출력하고 끝에 줄바꿈을 자동으로 붙여 줍니다. 가볍게 뭔가를 찍어 볼 때 가장 편한 방식이죠.

텍스트 모드와 바이너리 모드

open은 기본적으로 텍스트 모드로 동작합니다. 이때 Python이 바이트를 문자열로 디코딩하고(요즘 환경에서는 기본값이 UTF-8입니다) 줄바꿈 문자도 알아서 변환해 줍니다.

이미지, PDF, 컴파일된 파일처럼 텍스트가 아닌 데이터를 다룰 때는 모드에 "b"를 붙여서 바이너리 모드로 열어야 합니다:

with open("image.png", "rb") as f:
    data = f.read()

print(len(data))  # number of bytes

with open("image_copy.png", "wb") as f:
    f.write(data)

바이너리 모드로 열면 str 대신 bytes 객체가 반환되며, 파이썬이 줄바꿈 문자에 손대지 않습니다.

인코딩 지정하기

텍스트 파일을 다룰 때는 인코딩을 명시적으로 지정하는 게 좋습니다. 2026년 기준으로는 거의 대부분 UTF-8이 정답입니다:

with open("notes.txt", encoding="utf-8") as f:
    contents = f.read()

만약 윈도우 전용 환경에서 만들어진 레거시 파일을 다룬다면 cp1252latin-1 인코딩도 종종 마주치게 됩니다. 인코딩을 잘못 추측하면 글자가 깨지거나 UnicodeDecodeError가 발생하죠.

pathlib: 파일 경로를 다루는 모던한 방법

표준 라이브러리의 pathlib 모듈을 쓰면 문자열로 경로를 직접 조작할 때보다 훨씬 깔끔한 API를 사용할 수 있습니다:

from pathlib import Path

path = Path("notes.txt")

# Simple read and write.
contents = path.read_text(encoding="utf-8")
path.write_text("new contents\n", encoding="utf-8")

# Build paths without worrying about / vs \.
data_dir = Path("data")
log_path = data_dir / "today.log"

print(log_path)
print(log_path.exists())
print(log_path.suffix)       # ".log"
print(log_path.stem)         # "today"
print(log_path.parent)       # "data"

Path.read_text()write_text()는 파일을 한 번에 통째로 읽고 쓸 때 with open(...) as f 패턴을 대체하는 간편한 지름길입니다. 반면 줄 단위로 순회해야 할 때는 여전히 open이나 path.open()을 사용하면 됩니다.

간단한 엔드투엔드 예제

파일에서 항목 목록을 읽어 필터링한 뒤, 결과를 다른 파일에 저장하는 예시입니다:

from pathlib import Path

source = Path("items.txt")
destination = Path("filtered.txt")

items = source.read_text().splitlines()
kept = [item for item in items if item and not item.startswith("#")]

destination.write_text("\n".join(kept) + "\n")

print(f"Kept {len(kept)} items out of {len(items)}")

splitlines()join의 줄 단위 짝꿍이라고 보면 됩니다. 개행 문자를 기준으로 잘라내되 그 문자는 버리기 때문에, 어차피 다시 이어 붙일 거라면 꽤 유용합니다.

뭔가 잘못됐을 때

존재하지 않는 파일을 열려고 하면 FileNotFoundError가 발생합니다. 읽을 권한이 없는 파일에 접근하면 PermissionError가 발생하고요. 이 둘은 모두 OSError의 하위 클래스이고, OSError는 다시 Exception의 하위 클래스입니다. 예외를 제대로 처리하는 방법은 다음 페이지에서 자세히 다루겠습니다.

일단은 에러 처리가 대략 어떤 모습인지 살짝 미리 보고 가죠:

from pathlib import Path

path = Path("maybe.txt")

try:
    contents = path.read_text()
except FileNotFoundError:
    print("File doesn't exist — starting fresh.")
    contents = ""

print(repr(contents))

꼭 챙겨야 할 습관

  • open 후 직접 닫는 방식 대신 항상 with open(...)을 쓰세요.
  • 텍스트 파일은 항상 encoding=을 명시하세요. 기본은 UTF-8로 가는 게 안전합니다.
  • 큰 파일은 한 줄씩 순회하세요. .read()로 통째로 읽지 마세요.
  • 경로 다루기나 흔한 읽기/쓰기 패턴에는 pathlib을 쓰세요. 문자열로 씨름할 일이 확 줄어듭니다.

다음은 JSON입니다. 실제로 마주치는 텍스트 파일은 단순한 줄 모음이 아니라 구조화된 데이터인 경우가 대부분이고, 그중 가장 흔한 형식이 바로 JSON입니다. 지금까지 익힌 with open(...) 습관은 JSON을 다룰 때도 그대로 통합니다.

자주 묻는 질문

파이썬에서 파일을 어떻게 읽나요?

with문과 함께 open()을 쓰는 게 정석입니다. 블록이 끝나면 파일이 자동으로 닫히기 때문에 안전해요. with open('file.txt') as f: contents = f.read() 이렇게 하면 파일 전체를 문자열로 읽어옵니다. 한 줄씩 처리하고 싶다면 for line in f:처럼 파일 객체를 바로 순회하면 됩니다.

open 모드 'r', 'w', 'a'는 어떻게 다른가요?

'r'은 읽기 모드로 기본값이에요. 'w'는 쓰기 모드인데, 파일이 없으면 새로 만들고 있으면 기존 내용을 싹 지워버립니다. 'a'는 추가(append) 모드로, 기존 내용은 그대로 두고 뒤에 이어서 씁니다. 바이너리로 열려면 'b'를, 읽기+쓰기를 동시에 하려면 '+'를 붙이면 됩니다.

그냥 open() 말고 with open을 써야 하는 이유가 있나요?

with문을 쓰면 중간에 예외가 터져도 파일이 확실하게 닫히는 게 보장됩니다. with 없이 쓰면 직접 .close()를 호출해야 하고, 에러 상황에서도 빠뜨리지 않도록 try/finally까지 신경 써야 해요. with가 훨씬 안전하고 코드도 짧습니다.

Coddy로 코딩 배우기

시작하기