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()

만약 윈도우 전용 환경에서 만들어진 레거시 파일을 다룬다면 cp1252나 latin-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을 쓰세요. 문자열로 씨름할 일이 확 줄어듭니다.

자주 묻는 질문

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

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 프로그래밍 언어 일러스트

Coddy로 코딩 배우기

시작하기