오늘 다룰 주제는 지난 수업에서 배운 파일 입출력과 예외 처리에 관한 내용이다.
이때부터는 예습을 못한 내용이기 때문에
매일 과제를 해결하고 그 과정을 회고하는 내용 + 그날 배운 개념 정리를 담으려했으나
우선은 코드를 반복작성하며 몸에 익히는데에 집중하느라
뒤늦게 복습하는 느낌으로 작성하게 되었다.
그럼 먼저 파일 입출력에 대해 알아보자.
* 예시 코드의 출처는 오즈코딩스쿨이다
파일 입출력은 '프로그램'과 '외부 파일'간의 데이터 교환이 가능하게 해주고,
정보를 영구적으로 보존하고 공유할 수 있도록 해주는 기능이다.
예를 들어,
환자의 진료 기록이나 검사 결과같은 데이터들을 따로 파일로 저장할 수 있고 백업도 가능하다.
open()함수의 기본 문법은 아래와 같다.
file = open('파일명을 포함한 파일이 존재하는 위치', '모드', encoding='utf-8')
이 때 주의해야할 점은
작업을 다 수행하고 나면 반드시 .close()를 사용해 닫아주어야 한다는 점이다.
닫지 않으면 메모리 누수가 발생하며 다른 프로그램에서 접근하지 못하는 문제가 발생할 수 있다.
파일 모드의 종류
'r': 읽기 모드(기본값이며 기존 파일 내용을 읽기 위해 사용된다)'w': 쓰기 모드(새로운 내용으로 덮어쓰기 위함이며 기존 내용은 삭제된다)'a': 추가 모드(기존 내용 뒤에 새로운 내용을 추가하기 위해 사용된다)'r+': 읽기/쓰기 모드(파일을 읽고, 수정할 수 있다)* encoding='utf-8'는 텍스트를 컴퓨터가 이해할 수 있는 바이트로 변환하기 위함이다.
with 문을 사용하면 작업 후 파일을 자동으로 닫아주기 때문에 안전하게 파일을 처리할 수 있으며,
기본 문법은 아래와 같다.
with open('파일명을 포함한 파일이 존재하는 위치', '모드', encoding='utf-8') as file:
작업 내용
medical_records.txt라는 파일이 현재 폴더에 있다고 가정해보자
전체 내용을 읽고 싶다면 아래와 같이 작성해줄 수 있다.
with open('medical_records.txt', 'r', encoding='utf-8') as file:
content = file.read() # 전체 파일 내용
print(content)
with open('medical_records.txt', 'r', encoding='utf-8') as file:
first_line = file.readline().strip() # .strip()은 불필요한 공백 제거를 위함
print(f"첫 번째 기록: {first_line}")
.readlines()를 사용하면 모든 줄을 리스트로 읽을 수 있다.
with open('medical_records.txt', 'r', encoding='utf-8') as file:
all_lines = file.readlines() # 모든 줄을 리스트로 가져옴
for i, line in enumerate(all_lines, 1): # 반복문을 돌며 (줄 번호: 내용) 출력
print(f"{i}번째: {line.strip()}")
n = 2 # 원하는 줄
# 방법 1
with open('medical_records.txt', 'r', encoding='utf-8') as file:
lines = file.readlines()
print(lines[n-1]) # 인덱스 번호라 -1 필요
print(f"{'='*30}\n")
# 방법 2
import linecache
line = linecache.getline('medical_records.txt', n)
print(line)
위의 두 방법 중 편한 것을 사용하면 된다.
with open('medical_records.txt', 'r', encoding='utf-8') as file:
for line_num, line in enumerate(file, 1): # 파일을 한 줄씩 순회
record = line.strip() # 현재 줄의 진료기록
print(f"환자 {line_num}: {record}")
with open('prescription.txt', 'w', encoding='utf-8') as file:
prescription_data = "환자: 박환자\n의사: 김의사\n처방: 혈압약 1일 2회\n"
file.write(prescription_data)
모드를 'w'로 두고 file.write()를 하면 된다.
with open('prescription.txt', 'a', encoding='utf-8') as file:
additional_info = "\n복용기간: 30일\n주의사항: 식후 복용"
file.write(additional_info)
모드를 'a'로 두고 file.write()를 하면 된다.
patient_list = ["김환자(고혈압)\n", "이환자(당뇨병)\n", "박환자(감기)\n"]
with open('patient_list.txt', 'w', encoding='utf-8') as file:
file.writelines(patient_list)
위와 같이 여러 줄로 미리 작성된 것을 한번에 쓰고 싶으면 file.writelines()를 쓰면 된다.
medicines = ['혈압약', '당뇨약', '감기약', '진통제']
with open('medicine_list.txt', 'w', encoding='utf-8') as file:
for medicine in medicines:
file.write(f"{medicine}\n") # for문을 돌며 줄바꿈 해가며 작성됨
앞서 파일을 불러올 때 아래와 같이 불러온다고 했다.
with open('파일명을 포함한 파일이 존재하는 위치', '모드', encoding='utf-8') as file:
작업 내용
이 때 '파일명을 포함한 파일이 존재하는 위치'를 처음 작성해주어야 하는데
위의 예시들에서는 내가 작업하고자하는 파일이 현재 폴더에 저장되어있다는 전제하에
파일명만 작성해주었다.
current_folder = "patient_records.txt"
sub_folder = "backup/patient_backup.txt"
# 현재 폴더에 환자 기록 저장
with open(current_folder, 'w', encoding='utf-8') as file:
file.write("김환자 - 고혈압\n이환자 - 당뇨병\n")
# 하위 폴더에 백업 저장
import os
os.makedirs("backup") # backup폴더 생성
with open(sub_folder, 'w', encoding='utf-8') as file:
file.write("백업 완료: 2024-03-15\n")
예외 처리는 프로그램을 사용하는 동안 발생할 수 있는 오류를 적절히 처리하여
시스템 안정성을 보장하기 위해 마련하는 보험같은 개념이다.
try 블록에서 오류가 발생하면 except 블록이 실행되는 구조로
예외가 발생할 수 있는 코드를 안전하게 실행시킬 수 있도록 해주며 기본 문법은 아래와 같다.
try:
# 오류가 발생할 수 있는 코드
except 특정 예외타입:
# 오류가 발생했을 때 실행할 코드
except Exception as e:
# 예외 객체를 e로 받아서 사용
이건 과제를 풀며 작성한 코드를 보면 더 이해가 빠르다.

[캡쳐 1-1. 과제 요구 사항]

[캡쳐 1-2. 작성한 코드 비교]
추가로 finally블록은 예외 발생 여부와 관계 없이 항상 실행되는 코드 블록으로써
반드시 실행되어야 하는 작업에 사용해줄 수 있다.
| 예외 타입 | 발생 원인 | 해결 방법 |
|---|---|---|
| FileNotFoundError | 파일이 존재하지 않음 | 파일 경로 확인, 새 파일 생성 |
| PermissionError | 파일 접근 권한 없음 | 권한 요청, 다른 위치 사용 |
| IsADirectoryError | 파일 대신 폴더를 열려고 함 | 올바른 파일 경로 지정 |
| ValueError | 데이터(값)이 잘못되었음 | 데이터 수정하여 입력 |
| UnicodeDecodeError | 잘못된 인코딩으로 읽기 | UTF-8 인코딩 지정 |
| OSError | 운영체제 관련 오류 | 시스템 상태 확인 |
| IOError | 입출력 일반 오류 | 파일 상태 및 연결 확인 |
* raise를 사용하면 일부러 에러를 발생시킬 수 있다.([캡쳐 1-2]참고)
예외 처리를 잘 해 줄수록 보다 안정성 있게 코드를 실행시킬 수 있다.
그리고 그 능력은 직접 에러를 경험하면서 인사이트가 넓어진다.
내가 과제를 하며 다른 에러의 가능성을 생각하지 못했던 것처럼 말이다.
이번 내용을 배우고 과제를 하며
좀 더 많은 경험을 쌓아서 시야를 넓혀야겠다는 생각을 하게 되었다.