open()의 모드를 중심으로 정리
'r': 읽기(기본값)
'w': 쓰기(기존 파일 삭제 후 새로 생성)
'a': 추가(append)
'x': 파일이 없을 때만 생성
'b': 바이너리 모드
't': 텍스트 모드(기본값)
'+': 읽기 + 쓰기
모드들
f = open('LICENSE', 'r')
print(f.read())
f = open('LICENSE')
print(f.read())
first_line
second_line
third_line
읽기 기본 사용예시
open의 모드 기본값이 'r'이기 때문에 생략해도됨
모드 기본값은 'r'(읽기)이면서 't'(텍스트모드)임
read는 전체 읽기
f = open('LICENSE', 'r')
print(f.read(12))
first_line
s
모드의 기본값이 t(텍스트 모드)이기 때문에 디코딩된 문자열 기준으로 size만큼 출력(각 줄 끝에 있는 \n포함 12자)이고 b(바이너리 모드)면 바이트 수
size -1는 전체읽기
f = open('Korean.txt', 'r')
print(f.read(2))
Traceback (most recent call last):
File "C:\Users\MSI\PythonStudy\main.py", line 3, in <module>
print(f.read(2))
~~~~~~^^^
UnicodeDecodeError: 'cp949' codec can't decode byte 0x80 in position 2: illegal multibyte sequence
한글 출력시 에러가 발생하는 케이스
대부분의 파일이 utf-8로 저장되어 있는데 파이썬이 cp949로 디코딩하려고 해서 발생한 오류
f = open('Korean.txt', 'r', encoding='utf-8')
print(f.read(2))
가나
encoding='utf-8' 입력시 정상 출력
import locale
print(locale.getpreferredencoding())
cp949
인코딩을 직접 명시하지 않았을때 기본값으로 들어가는 방식은 locale 모듈을 사용해 확인 가능
윈도우 한국어 기본 방식은 cp949이지만 사실상 utf-8이 표준에 가깝기 때문에 파라미터에 명시해주는게 좋음
f = open('LICENSE', 'r')
print(f.readline())
print(f.readline())
print(f.readline())
first_line
second_line
third_line
readline은 한 줄씩 읽고 각 줄 끝에 있는 개행 문자까지 포함해서 읽음
여기에 print()도 자동으로 개행을 붙이기 때문에 한 줄 건너띄고 다음 라인이 출력됨
f = open('LICENSE', 'r')
print(f.readline().strip())
print(f.readline(), end='')
print(f.readline().strip())
first_line
second_line
third_line
이럴땐 strip() 혹은 end=''로 해결(print의 end 기본값은 '\n')
f = open('LICENSE')
print(f.readline(2))
fi
read와 마찬가지로 파라미터에 넣는 값만큼의 글자수 출력
f = open('LICENSE', 'r')
print(f.readlines())
['first_line\n', 'second_line\n', 'third_line']
readlines는 각 줄을 요소로 가진 리스트를 리턴
내부적으로 readline을 반복 호출
readlines는 파일이 큰 경우에서는 잘 쓰이지 않음
이유는 이미 파일이 iterator인 상태에서 필요없는 리스트를 생성해 파일 크기만큼의 메모리 사용이 있기 때문
그리고 리스트를 생성하기 위해 파일 전체를 읽는 방식이라 실시간 스트리밍 방식에도 부적합
f = open('LICENSE')
for i in f:
print(i.strip())
f는 이미 iterator이기 때문에 그냥 바로 한줄씩 돌리면 된다.
f = open('LICENSE')
print(f.readlines(5))
['first_line\n']
파라미터는 read, readline의 size가 아닌 hint임
hint는 줄 개수X, 정확히 읽어야 하는 바이트X
읽은 데이터의 누적 길이가 hint 이상이 될 때까지 줄 단위로 읽음
f = open('LICENSE')
print(f.readlines(11))
print(f.readlines(1))
['first_line\n', 'second_line\n']
['third_line']
readlines(11)에서 누적길이가 11 이상 될때까지 줄 단위로 읽어서 첫줄과 둘째줄 읽음
readlines(1)에서 누적길이 1 이상 될때까지 줄 단위로 읽어서 셋째줄 읽음
with open('LICENSE', 'r') as f:
print(f.read())
개발을 하다보면 os로부터 한정된 자원을 받고 사용이 끝나면 반드시 반환해줘야 하는 경우가 많음
open 함수를 사용할때는 os로부터 fd(파일 디스크립터)라는 자원을 받음
with를 사용하면 블록이 끝나면 내부적으로 close()함수가 실행되어 fd를 os에 반환함
이러한 방식이 open 함수의 실무 기본 사용법
f = open('LICENSE', 'r')
print(f.read())
f.close()
close()를 직접 사용해 반환하는 방식도 가능
with 키워드를 사용한 예시는 이 예시와 결과가 같지만 예외 상황이 발생할 경우 close()가 실행되지 않을 수 있어 with 사용이 더 안전
mgr = open('LICENSE', 'r')
f = mgr.__enter__()
try:
print(f.read())
finally:
mgr.__exit__(...)
with의 내부는 이런식으로 예외처리가 되어있기에 close가 무조건 실행
finally에서 __exit__ 를 호출하면 close() 실행함
class MyResource:
def __enter__(self):
print('자원 획득')
return self
def __exit__(self, exc_type, exc_val, _exc_tb):
print('자원 해제')
with MyResource() as r:
print('작업 중')
자원 획득
작업 중
자원 해제
__enter__() 와 __exit__(exc_type, _exc_val, _exc_th) 메서드가 있는 객체라면 with 사용가능
exc_type: 예외 타입
exc_val: 예외 객체
exc_tb: traceback 객체
추가적으로 알아야 하는 개념들은 따로 주제빼서 작성하기로