데이터 기록(파일, DB, 피클링) 및 팁
*본문은 <파이썬 정복>(김상형 저, 한빛미디어, 2018), <씽크 파이썬>(앨런 다우니, 길벗, 2017)을 읽고 공부한 내용을 메모한 것입니다.
1. 파일
프로그램이 데이터를 관리하는 가장 간단한 방법.
open, write, close 등의 함수는 일단 생략(* 이렇게 세가지 함수가 있는 이유: 파일을 저장하는 디스크는 메모리보다 느리기 때문에 원활한 입출력을 위해 준비 과정이 필요!)
*파일 객체가 따로 있으며, 이터레이터 중 하나다. 따라서 txt파일을 open만 한 상태에서는 문자열 자료형이라고 할 수 없다. 또한 메서드도 당연히 문자열 메서드 적용할 수 없음.
1) read 함수 시리즈
- read만 하면, 읽는 파일 용량이 클 경우 메모리를 많이 소모하므로 text = f.read(10) 과 같은 방식으로 읽을 양을 조절하여 읽어야 한다.
- readline 함수는 한 줄 씩 읽고 파일 마지막에 도달하면 빈 문자열 리턴. 그래서 아래에 나온 if not과 같은 조건문을 잘 사용한다.
f = open("live.txt", "rt")
text = ""
line = 1
while True:
row = f.readline()
if not row: break
text += str(line) + ":" + row
line += 1
f.close()
print(text)
- readlines 함수는 파일 전체를 읽어 한 줄씩 문자열로 만들어 리스트를 리턴한다. 읽는 파일의 각 줄 끝에 개행 문자가 포함되어 있는데 그것을 출력하고 싶지 않은 경우, print(line, end = '')와 같은 코드를 작성하면 된다. 리스트에 대해선 아래에 작성한 코드처럼 루프를 돌 수 있다.
- 파일도 리스트와 같은 컬렉션이므로 파일 자체에 대해 루프를 돌 수도 있다.
f = open("live.txt", "rt")
for line in f:
print(line, end = '')
f.close()
2) 옵션(모드)
- 'a' 옵션은 기존 내용을 그대로 유지하고 뒤에 덧붙이며, 이를 위해 파일을 열자마자 입출력 위치를 파일 제일 끝으로 보낸다.
- 반면 'w' 옵션은 파일이 이미 있으면 '덮어쓰고' '새로 만든다'.
- 'x' 옵션은 파일에 기록하되 파일이 이미 있으면 실패.
(함수명)(파일경로, 옵션)에서 옵션을 작성한 뒤엔 파일의 종류를 지정하는 문자를 쓴다. t는 텍스트파일, b는 이진 파일. 이진파일은 있는 그대로 쓰는 데 비해 텍스트 파일은 개행 코드를 운영체제에 맞게 바꿔 준다. 디폴트는 텍스트 파일 읽기 모드인 rt이다.
3) 입출력 위치
- 순차 접근: 파일 객체가 다음 입출력 위치를 정확하게 기억한다는 특징을 이용해 조금씩 반복적으로 읽는 방식
- 임의 접근: 입출력 위치를 바꿔가며 파일의 원하는 부분을 자유롭게 액세스하는 방식. 입출력 위치를 조사할 때는 tell, 위치를 변경할 땐 seek(위치, 기준) 함수를 사용한다. 기준이 0이면 파일 처음, 2이면 끝에서부터, 1이면 현재 위치를 기준으로 한다. 아래 코드는 앞 몇 자를 건너뛴 후 나머지를 읽는다. 정확히는 12바이트를 건너뛴다.
f = open("live.txt", "rt")
f.seek(12,0)
text = f.read()
f.close()
print(text)
임의 접근은 가변적인 텍스트 파일에는 적용하기 어렵고, 길이가 일정한 이진 파일에 주로 사용한다. seek 함수는 음악이나 동영상 파일의 재생 위치를 건너뛸 때 사용한다!
4) 내용 추가
일일이 close 함수를 추가하는 것의 번거로움을 위해 with~ as가 있단 거 알지? 자원을 확실히 정리할 땐 try~finally 구문을 이용하지만, 파일 입출력 시에는 with~as가 더 편하다.
with open("live.txt", "rt") as f:
text = f.read()
5) 예외 처리
열다보면 잘못되는 일이 많기 때문에 미리 에러를 잡아두는 것이 낫다.
try:
f = open('bad_file')
except FileNotFoundError:
print('파일이 없습니다.')
finally:
f.close()
2. 파일명과 경로
이를 위한 함수는 os 모듈서 제공.
os.getcwd(): current working dir인가보군. 현재 디렉터리 이름을 반환한다.
os.path.abspath(파일명): 파일의 절대 경로 반환
os.path.exists(파일명): 파일/디렉터리 존재 여부 검사
os.path.isdir(경로명): 경로가 디렉터리인지 검사하여 bool 반환
os.path.isfile(경로명): 경로가 파일인지 검사하여 bool 반환
os.listdir(디렉토리명): 해당 디렉터리의 파일과 다른 디렉터리의 목록을 반환한다.
3. Database
데이터베이스는 데이터 저장에 특화된 파일이다. 대다수 데베는 사전과 비슷한 형태로 구조화되어 있다. 사전과 차이점은 데베는 디스크에 저장되고, 프로그램이 종료된 뒤에도 유지된다는 점이다. dbm 모듈은 데이터베이스 파일을 생성하고 업데이트하는 데 필요한 인터페이스를 제공한다.
>>> import dbm
db = dbm.open('captions', 'c')
'c' 모드는 데베가 없으면 생성하라는 뜻이다. 새 항목을 생성하면 dbm은 파일을 업데이트한다.
>>> db['cleese.png'] = 'Photo of John Cleese.'
항목 중 하나에 접근하면 dbm은 파일을 읽어온다.
>>> db['cleese.png']
b'Photo of John Cleese.'
결과는 바이트 객체가 되므로 b로 시작한다.
주의할 점이 있다. keys, items 같은 사전의 일부 메서드는 데이터베이스 객체와 동작하지 않는다는 점이다. 대신 for루프를 사용한 이터페이션과 함께 하면 데이터베이스 객체와 동작한다.
for key in db:
print(key, db[key])
파일과 마찬가지로 작업이 끝나면 데이터베이스를 닫아야 한다.
>>> db.close()
4. 피클링
dbm의 제약 때문에 키와 값은 문자열이나 바이트만 써야 한다. 다른 타입을 사용하려 하면 오류가 발생한다. pickle 모듈을 사용하면 이를 해결할 수 있다.이 모듈은 어떤 타입의 객체라도 데베 저장에 적합한 문자열로 변환하고, 변환된 문자열을 다시 객체로 변환할 수 있다. 시간관계상 일단 요정도로 하고 다음으로 패스
5. 파이프
셸은 일반적으로 시스템을 이동하거나 애플리케이션을 실행할 수 있는 명령을 제공한다. cd, ls 등. 셸에서 실행할 수 있는 모든 프로그램은 파이썬에서 파이프 객체를 사용해 실행 가능하며, 파이프 객체는 실행 중인 프로그램을 표현한 것이다!
6. 팁
파일을 읽고 쓸 때 공백 문제가 발생할 수 있다. 공백, 탭, 세줄 문자는 일반적으로 보이지 않기 때문에 이런 오류는 디버깅하기 어렵다.
>>> s = '1 2\t 3\n 4'
>>> print(s)
1 2 3
4
내장 함수 repr가 이럴 때 유용하다. 객체를 인수로 받아서 객체의 문자열 표현을 반환한다. 공백 문자 등을 역슬래시 시퀀스로 표현해준다.
>>> print(repr(s))
'1 2\t 3\n 4'