open(path, mode='r', encoding=None) 가 읽거나 쓸 file 객체 반환. 가장 중요한 두 인자 — 모드와 인코딩. 모드는 읽기/쓰기 그리고 텍스트/바이너리 알려줘. 인코딩은 바이트와 텍스트 변환 — UTF-8 이 현대 디폴트, 다른 거 거의 안 필요해.
모드 문자 — 결합되는 5 글자
r 읽기 (디폴트), w 쓰기 (먼저 truncate), a 추가, x 생성-only (있으면 실패), + 읽기+쓰기, b 바이너리, t 텍스트 (디폴트). 조합 — rb 바이너리 읽기, w+ 쓰기+읽기, a+b 추가+읽기+바이너리. 텍스트/바이너리 차이 중요 — 텍스트 모드가 인코딩/디코딩 + 줄바꿈 변환, 바이너리 모드는 raw 바이트.
항상 with 문
with open(path) as f: 가 블록 안에서 예외 raise 되어도 파일 닫힘 보장. 대안 — f = open(path); ... f.close() — 는 open 과 close 사이 예외 안 날 때만 맞음. 약속할 수 없는 제약. with 써. 끝.
encoding 인자 — UTF-8 디폴트가 사실 X
놀라움 — open() 이 지정 안 할 때 시스템 디폴트 인코딩 사용, Windows 에선 종종 cp1252 같은 거. 크로스플랫폼 코드 물려. 해결 — open(path, encoding='utf-8'), 텍스트 읽기/쓰기 항상. Python 3.11+ 가 encoding="locale" 추가해서 locale 기반 동작 명시적.
주의: 같은 파일에 텍스트와 바이너리 모드 시간 다르게 섞으면 버그 레시피. 하나 골라 박아. 둘 다 필요하면 두 파일 객체 또는 명시적 seek-and-reopen. r+b 로 전환하지 마.
Code
open() — 텍스트 읽기/쓰기·python
# 파일 통째 읽기
with open("/etc/hostname", encoding="utf-8") as f:
content = f.read()
print(content.strip())
# 쓰기 — overwrite
with open("/tmp/out.txt", "w", encoding="utf-8") as f:
f.write("hello\n")
f.write("world\n")
# Append
with open("/tmp/out.txt", "a", encoding="utf-8") as f:
f.write("more\n")
# 생성-only — 있으면 실패
try:
with open("/tmp/out.txt", "x", encoding="utf-8") as f:
f.write("여기까지 안 옴")
except FileExistsError as e:
print("이미 존재:", e)
줄 단위 읽기 — streaming idiom·python
# 큰 파일에 이거 X
# data = open("big.log", encoding="utf-8").read() # 전부 로드
# 이거 — file 객체가 줄 단위로 iterable
with open("/tmp/out.txt", encoding="utf-8") as f:
for line in f:
print("got:", line.rstrip("\n"))
# .readlines() — 줄 list, eager
with open("/tmp/out.txt", encoding="utf-8") as f:
lines = f.readlines()
print(lines) # ['hello\n', 'world\n', 'more\n']
바이너리 모드 — 바이트 in/out·python
# 바이너리 파일 읽기
with open("/bin/ls", "rb") as f:
header = f.read(4)
print(header) # b'\x7fELF' on Linux/macOS
# 바이트 쓰기
with open("/tmp/raw.bin", "wb") as f:
f.write(b"\xDE\xAD\xBE\xEF")
# 텍스트와 바이너리는 다른 파일 모드
try:
with open("/tmp/raw.bin", "r") as f: # 텍스트 모드!
f.read() # UnicodeDecodeError 가능
except UnicodeDecodeError as e:
print("예상대로:", e)
Seek + tell — 위치 변경·python
# 파일 안 seek 하려면 read+write 로 열기
with open("/tmp/seek.txt", "w+", encoding="utf-8") as f:
f.write("hello world")
print("위치:", f.tell()) # 11
f.seek(0)
print(f.read(5)) # 'hello'
f.seek(6)
print(f.read()) # 'world'
# 멀티바이트 컨텐츠에 정확한 byte seeking 은 바이너리 모드 필요
텍스트 파일 항상 인코딩 지정·python
# Linux 에선 작동, Windows 시스템 locale 이 UTF-8 안 만들면 깨질 수 있음
# with open("data.txt") as f:
# contents = f.read()
# 항상 인코딩 지정
with open("/tmp/out.txt", encoding="utf-8") as f:
contents = f.read()
print(contents[:50])
# 3.11+ 가 명시적 'locale 사용' 위해 "locale" 추가 — 디폴트와 다름
# with open("data.txt", encoding="locale") as f: ...
세 프로그램 — (a) 파일 /tmp/quest_test.txt 생성, 세 줄 쓰기 (open + with). (b) 같은 파일 읽기로 열고 각 줄을 줄 번호와 함께 출력. (c) 네 번째 줄 추가, 다시 읽어서 네 줄 다 있는지 확인. 항상 encoding='utf-8' 지정. with 블록 사용.
Progress
Progress is local-only — sign in to sync across devices.