#!/usr/bin/env python
# coding: utf-8
# # 8. 텍스트와 바이너리 파일
# ## 8.1 두 가지 종류의 파일: 텍스트와 바이너리
# ![](images_skill_up/8-1.PNG)
# ![](images_skill_up/8-2.PNG)
# - 1) 저수준 (low-level) 파일 접근 모드
# - 텍스트 모드: 개행 문자가 자동으로 변역되어 개행-캐리지 리턴(\\n\\r) 쌍을 대체함
# - 개행 문자를 지닌 텍스트 파일을 보여줄 때 실제 줄바꿈하여 보여줌
# - 바이너리 모드: 위와 같은 대체 없음
#
#
# - 2) 저장되어지는 데이터 타입
# - 텍스트 모드: 표준 파이썬 문자열 (ASCII/UNICODE) 을 사용하여 읽기/쓰기 수행
# - 바이너리 모드: byte 타입을 사용하여 읽기/쓰기 수행
#
#
# - 3) 숫자 쓰기
# - 텍스트 모드: 모든 숫자 데이터는 문자열 타입으로 변환되어 저장됨
# - 바이너리 모드: 숫자 그 자체 byte 타입으로 저장됨
#
# ## 8.2 바이너리 파일을 사용하는 경우
# - struct 패키지
# - pickle 패키지 (이것만 알아도 됨)
# - shelve 패키지
# ## 8.3 파일/딕셔너리 시스템
# In[1]:
import os
# - 프로세스를 시작, 종료, 반복하는 함수: **spawn, kill, abort, fork**
# - 파일/디렉토리 시스템을 변경하거나 탐색하는 함수: **rename, removedirs, chroot, getcwd, rmdir, listdir, makedir, mkdir**
# - 파일 플래그와 다른 속성들을 수정하는 함수: **chflags, chmod, chown**
# - 환경 변수를 가져오거나 조정하는 함수: **getenv, getenvb, putenv**
# - 신규 시스템 명령어를 실행하는 함수: **exec**
# - 파일 I/O에 저수준 접근을 하는 함수: **open, read, write**
# In[3]:
print(os.getcwd())
# In[7]:
print(os.listdir(), len(os.listdir()))
# In[8]:
os.mkdir("my_dir")
# In[9]:
print(os.listdir(), len(os.listdir()))
# In[10]:
print(os.path.isfile("stock_load.py"))
# In[12]:
print(os.path.isfile("my_dir"))
# In[13]:
print(os.path.isdir("my_dir"))
# In[14]:
print(os.path.join("my_dir", "sub_dir_1", "sub_dir_2"))
# ## 8.4 파일을 열 때 발생하는 예외 다루기
# ### 다양한 파일 처리 모드
#
# > f = open(fname, 'r')
#
# - open 내장 함수의 두번째 인자 mode 설명
# - 두번째 인자 mode 생략시에는 읽기 전용(r) 모드로 설정
#
# | Mode | 간단 설명 | 자세한 설명
# |--------|-----------------------------|------------|
# | 'r' | 읽기 전용(기본 모드) | 파일 객체를 읽기 모드로 생성하고, 파일 포인터를 파일 처음 위치에 놓는다.|
# | 'w' | 쓰기 전용(기존 파일 내용 삭제) | 파일이 존재하지 않으면 새로운 파일을 쓰기 모드로 생성하고, 해당 파일이 이미 존재하면 내용을 모두 없에면서 쓰기 모드로 생성하고, 파일 포인터를 파일 처음 위치에 놓는다. |
# | 'a' | 파일 끝에 추가(쓰기 전용) | 파일이 존재하지 않으면 새롭게 파일을 생성하면서 쓰기 모드로 생성하고, 해당 파일이 이미 존재하면 파일 객체을 쓰기 모드로 생성하면서 파일 포인터를 파일의 마지막 위치에 놓는다. 따라서, 이후 작성되는 내용은 파일의 뒷 부분에 추가됨.|
# | 'r+' | 읽고 쓰기 | 파일 객체를 읽고 쓸 수 있도록 생성한다. 파일 포인터를 파일 처음 위치에 놓는다. |
# | 'w+' | 읽고 쓰기(기존 파일 내용 삭제) | 파일 객체를 읽고 쓸 수 있도록 생성한다. 파일이 존재하지 않으면 새로운 파일을 생성하고, 해당 파일이 이미 존재하면 내용을 모두 없에면서 생성하고, 파일 포인터를 파일 처음 위치에 놓는다.|
# | 'a+' | 읽고 쓰기(파일 끝에 추가) | 파일 객체를 읽고 쓸 수 있도록 생성한다. 파일이 존재하지 않으면 새롭게 파일을 생성하고, 해당 파일이 이미 존재하면 파일 객체을 생성하면서 파일 포인터를 파일의 마지막 위치에 놓는다 (그래서, 이후 작성되는 내용은 파일의 뒷 부분에 추가). |
# ### 파이썬 예외 처리 구문
#
# In[16]:
try:
fname = input('Enter file to read:')
f = open(fname, 'r')
print(f.read())
except FileNotFoundError:
print('File', fname, 'not found. Terminating.')
# In[ ]:
while True:
try:
fname = input('Enter file name: ')
if not fname: # 빈 문자열이 입력되면 종료한다.
break
f = open(fname) # 파일 열기를 시도한다.
print(f.read())
f.close()
break
except FileNotFoundError:
print('File could not be found. Re-enter.')
# In[ ]:
while True:
fname = input('Enter file name: ')
if not fname:
break
try:
f = open(fname) # 파일 열기를 시도한다.
except FileNotFoundError:
print('File could not be found. Re-enter.')
else:
print(f.read())
f.close()
break
# ## 8.5 'with' 키워드 사용하기
# - 파일을 Open한 이후 올바로 닫지 않고, 자원을 해제하지 않은 상태로 갑자기 종료가 되는 상황 발샐 가능
# - 파일 I/O를 잘 수행하다가 발생하는 예외 상황
# ### with 구문
#
#
# In[21]:
with open('stock_load.py', 'r') as f:
lst = f.readlines()
for thing in lst:
print(thing, end='')
# ## 8.6 읽기/쓰기 연산의 요약
# ![](tables_skill_up/t0801-1.PNG)
# ![](tables_skill_up/t0801-2.PNG)
# ## 8.7 텍스트 파일 작업 상세하게 알아보기
# In[22]:
with open('file.txt', 'w') as f:
f.write('To be or not to be\n')
f.write('That is the question.\n')
f.write('Whether tis nobler in the mind\n')
f.write('To suffer the slings and arrows\n')
with open('file.txt', 'r') as f:
print(f.read())
# In[23]:
with open('file.txt', 'r') as f:
s = ' ' # 빈 칸으로 초기화한다.
while s:
s = f.readline()
print(s)
# In[24]:
with open('file.txt', 'r') as f:
s = ' ' # 빈 칸으로 초기화한다.
while s:
s = f.readline()
s = s.rstrip('\n')
print(s)
# In[25]:
with open('file.txt', 'r') as f:
str_list = f.readlines()
for s in str_list:
print(s, end='')
# ## 8.8 파일 포인터('seek') 사용하기
# - 파일에 대한 순차 접근이 아닌 임의 접근이 필요할 때 사용 (실용적으로는 잘 활용되지 않음)
#
# > f.seek(pos, orig)
# - orig로 지정된 위치를 기준으로 파일 내 임의 접근 위치 pos 로 이동한다.
# - orig
# - 0: 파일의 시작 지점
# - 1: 현재 위치
# - 2: 파일의 끝 지점
#
# > f.tell()
# - 파일 처음 시작 부터 계산하여 현재 위치를 반환한다.
# In[33]:
with open('file.txt', 'r') as f:
print(f.seekable())
print(f.read(5))
print(f.tell())
print("*" * 80)
f.seek(0, 0)
print(f.tell())
print(f.read(5))
# ## 8.9 RPN 프로젝트 안에서 텍스트 읽기
#
# ### (생략)
# ## 8.10 바이너리 직접 읽기/쓰기
# - 바이트 타입의 값 생성
# - 문자열 바로 앞에 b 접두어 표기
# - 문자열 내용에 숫자만 있는 경우 일반적으로 \\x와 함께 16진수로 바이트(8비트) 표기
# In[59]:
with open('my.dat', 'wb') as f:
b = b'\x01\x02\x03\x0f\x10\x1f'
print(type(b))
f.write(b)
b = b'hello'
print(type(b))
f.write(b)
# In[60]:
print(os.listdir())
# In[61]:
with open('my.dat', 'rb') as f:
bss = f.read()
print(type(bss), len(bss))
for i in bss:
print(i, end=' ')
# ### 바이너리 데이터를 저수준 (low-level)으로 직접 쓰고 읽는 작업은 잘 하지 않는다.
# ### 대신 다음과 같은 고수준 (high-level) 방식으로 쓰고 읽는다.
# #### 1. struct 패키지 사용
# #### 2. pickle 패키지 사용 (가장 많이 이용하는 패키지)
# #### 3. shelve 패키지 사용
# ## 8.11 데이터를 고정-길이 필드로 변환하기 (struct)
# #### (생략)
# ## 8.12 피클링 패키지 사용하기
# ![](images_skill_up/8-3.PNG)
# In[62]:
import pickle
with open('goo.dat', 'wb') as f:
pickle.dump([1, 2, 3], f)
pickle.dump('Hello!', f)
pickle.dump(3.141592, f)
# In[63]:
with open('goo.dat', 'rb') as f:
a = pickle.load(f)
b = pickle.load(f)
c = pickle.load(f)
print(type(a), a)
print(type(b), b)
print(type(c), c)
# In[66]:
if type(a) == list:
print('The length of a is {0}'.format(len(a)))
# - pickle의 유일한 단점: pickle로 여러 객체를 저장(dump)한 파일 내에 얼마나 많은 객체가 있는지 직접 확인할 수 없음
# - load 를 여러번 호출하여 객체를 가져오다 보면 더 이상 객체를 가져올 수 없을 때 --> **EOFError 예외 발생**
# In[67]:
loaded = []
with open('goo.dat', 'rb') as f:
while True:
try:
item = pickle.load(f)
except EOFError:
print('Loaded', len(loaded), 'items.')
break
print(type(item), item)
loaded.append(item)
# ## 8.13 shelve 패키지 사용하기
# (생략)
# ***
# ***
# ## [추가 내용] 파일과 디렉토리 다루기
# ***
# ***
# ***
# ### 파일 다루기
# ***
# #### 1-1 파일 목록 얻기
# - os.listdir('경로')
# - 디렉토리 안에 들어 있는 각 파일 목록 반환
# In[68]:
import os
print(os.listdir('.')) # 현재 디렉토리의 파일 목록 얻기
print()
print(os.listdir('../')) # 현재 디렉토리의 부모 디렉토리의 파일 목록 얻기
# #### 1-2 파일 종류 알아보기
# - os.path 모듈의 다음 함수들은 파일의 종류를 판단하여 True 또는 False를 반환한다.
# - isfile(filepath)
# - 순수 파일이면 True
# - isdir(filepath)
# - 디렉토리이면 True
# - islink(filepath)
# - 심볼릭링크이면 True
# In[69]:
import os
def filetype(fpath):
print(fpath, ':', end="")
if os.path.isfile(fpath):
print('Regular file')
if os.path.isdir(fpath):
print('Directory')
if os.path.islink(fpath):
print('Symbolic link')
flist = os.listdir('.')
for fname in flist:
filetype(fname)
# #### 1-3 파일 조작하기
# #### 1) 파일 이름 변경하기
# - os.rename(old_filepath, new_filepath)
# In[4]:
s = """Its power: Python developers typically report
they are able to develop applications in a half
to a tenth the amount of time it takes them to do
the same work in such languages as C."""
with open('t.txt', 'w') as f:
f.write(s) # 문자열을 파일에 기록
# In[5]:
import os
os.rename('t.txt', 't1.txt') # t.txt를 t1.txt로 바꾼다
# #### 2) 파일 이동하기
# - os.rename(old_filepath, new_filepath)
# In[6]:
os.mkdir('example')
# In[7]:
os.rename('t1.txt', './example/t1.txt') # 현재 작업 디렉토리의 t1.txt를 example에 t1.txt이름으로 옮긴다.
# #### 3) 파일 복사하기
# - shutil 모듈 활용
# - shutil.copyfile(src_filepath, dest_filepath)
# In[9]:
import shutil
s = """Its power: Python developers typically report
they are able to develop applications in a half
to a tenth the amount of time it takes them to do
the same work in such languages as C."""
with open('t.txt', 'w') as f:
f.write(s) # 문자열을 파일에 기록
shutil.copyfile('t.txt', 't_copied.txt')
# #### 1-4 파일 이름 다루기
# #### 1) 상대 경로를 절대 경로로 변환하기 [중요]
# - os.path.abspath(상대경로)
# - 실제 파일 존재와는 무관하게 절대경로로 변경함
# In[10]:
import os
print(os.path.abspath('o.txt'))
# #### 2) 주어진 경로의 파일이 존재하는지 확인 [중요]
# - os.path.exists(filepath)
# In[11]:
f = '/Users/yhhan/git/python-e-learning/sample.txt'
print(os.path.exists(f))
print(os.path.exists('sample.txt'))
print(os.path.exists('asdf.txt'))
# #### 3) 현재/부모 디렉토리를 가리키는 이름 얻기
# In[12]:
print(os.curdir) #현재 디렉토리
print(os.pardir) #부모 디렉토리
# #### 4) 디렉토리 분리 문자 얻기
# In[13]:
print(os.sep)
# #### 1-5 경로명 분리하기
# #### 1) 경로와 파일명으로 분리
# In[15]:
f = '/Users/yhhan/git/python-e-learning/t.txt'
print(os.path.basename(f)) # 파일명만 추출
print(os.path.dirname(f)) # 디렉토리 경로 추출
# #### 2) 경로명과 파일명을 한번에 분리
# In[16]:
print(os.path.split(f))
# #### 3) MS 윈도우즈에서 드라이브명과 파일 경로명을 분리
# In[17]:
print(os.path.splitdrive(f))
# #### 4) 확장자 분리
# In[18]:
print(os.path.splitext(f))
# #### 1-6 경로명 생성하기 [중요]
# - Linux and Mac
# In[19]:
path = os.path.join("/", "Users", "yhhan", "git", "python-e-learning", "t.txt")
print(path)
# - Windows
# In[20]:
path = os.path.join("c:\\", "Users", "yhhan")
print(path)
# ***
# ### 디렉토리 다루기
# ***
# #### 2-1 디렉토리에 관련된 일반 작업
# #### 1) 현재 작업 디렉토리 알아보기
# In[21]:
import os
print(os.getcwd())
# #### 2) 작업 디렉토리 변경하기
# In[22]:
path = os.path.join("/", "Users", "yhhan", "Public")
#path = os.path.join("c:\\", "Users", "yhhan", "Public")
os.chdir(path)
print(os.getcwd())
# #### 3) 디렉토리 만들기
# In[26]:
import os
os.mkdir('temp_new') # 0755 기본 모드(rwxr-xr-x)로 만들어짐
get_ipython().run_line_magic('ls', '-al temp_new')
# os.mkdir('temp2', 0700) # 0700 모드(rwx------)로 만들어짐
os.mkdir('temp_new_2', 0o700)
os.makedirs('temp_new_2/level1/level2') #0755 기본 모드, 중간에 필요한 디렉토리도 모두생성
# In[27]:
import os
os.mkdir('temp3', 0o700)
path = os.path.join("temp3", "level1", "level2")
os.makedirs(path) #0755 기본 모드, 중간에 필요한 디렉토리도 모두생성
# #### 4) 디렉토리 삭제
# In[28]:
os.rmdir('temp') #디렉토리에 내용이 없을 때 삭제가능
# In[29]:
os.rmdir('temp3') #디렉토리에 다른 파일이 있으면 삭제할 수 없음
# #### 5) 다단계 디렉토리 삭제
# - os.removedirs(filepath)
# - filepath에 지정된 디렉토리들 중 맨 오른쪽 디렉토리 부터 차례차례로 삭제한다.
# - 디렉토리에 다른 파일이 있으면 삭제하기 않고 중단
# In[30]:
os.removedirs('temp2/level1/level2')