키보드 입력과 텍스트 파일 읽기·쓰기의 기초
이번 강의가 끝나면 다음을 할 수 있어야 한다.
with open()을 사용하여 텍스트 파일을 쓰고 읽을 수 있다.r, w, a 모드의 차이를 설명할 수 있다.print()는 값을 화면에 출력하고, input()은 키보드 입력을 문자열로 받는다.
name = input("이름을 입력하세요: ")
print("안녕하세요,", name)
input()의 결과는 항상 문자열이다.따라서 다음 코드는 숫자 덧셈을 하지 않는다.
value1 = input("첫 번째 값: ")
value2 = input("두 번째 값: ")
print(value1 + value2)
2와 3을 입력하면 문자열을 연결한 23이 출력된다. 숫자로 계산하려면 int() 또는 float()로 변환해야 한다.
value1 = float(input("첫 번째 값: "))
value2 = float(input("두 번째 값: "))
print(value1 + value2)
빈 줄을 입력할 때까지 여러 값을 더하는 프로그램은 다음과 같다.
total = 0.0
while True:
text = input("값을 입력하세요. 종료하려면 Enter: ")
if text == "":
break
total += float(text)
print("합계:", total)
평균을 구하려면 합계뿐 아니라 입력한 값의 개수도 저장해야 한다.
total = 0.0 ## 합계 (float)
count = 0 ## 값의 개수 (integer)
while True:
text = input("값을 입력하세요. 종료하려면 Enter: ")
if text == "":
break
total += float(text)
count += 1
if count > 0:
average = total / count
print("평균:", average)
else:
print("입력된 값이 없습니다.")
계산 결과를 문자열 안에 넣을 때는 f-string을 사용하면 편리하다.
name = "Iron"
density = 7.87
print(f"The density of {name} is {density:.2f} g/cm^3")
{density:.2f}는 실수를 소수점 아래 둘째 자리까지 표시한다.
value = 9 / 6
print(f"{value:.1f}")
print(f"{value:.5f}")
Python 코드에서는 다음과 같은 % 포매팅을 볼 수도 있다.
print("The density of %s is %.2f g/cm^3" % (name, density))
변수와 출력 위치를 한눈에 확인하기 쉬운 f-string이 더욱 선호되는 방식이다. 실수에 %d를 사용하면 소수 부분이 표시되지 않으므로 주의한다.
Python에서는 open()으로 파일 객체를 만든 뒤 내용을 읽거나 쓴다.
open(파일이름, 모드, encoding="utf-8")
텍스트 파일에서는 한글을 안정적으로 다루기 위해 encoding="utf-8"을 명시하는 것이 좋다. 영문으로만 작성한다면 encoding을 생략해도 된다. open()으로 연 파일은 반드시 close()로 닫아야 한다. with 문을 사용하면 블록을 벗어날 때 자동으로 닫힌다.
| 모드 | 의미 | 파일이 없을 때 | 파일이 있을 때 |
|---|---|---|---|
"r" | 읽기(read) | 오류 발생 | 기존 내용 읽기 |
"w" | 쓰기(write) | 새 파일 생성 | 기존 내용 삭제 후 쓰기 |
"a" | 추가(append) | 새 파일 생성 | 기존 내용 끝에 추가 |
"rb" | 이진 파일 읽기 | 오류 발생 | bytes로 읽기 |
"wb" | 이진 파일 쓰기 | 새 파일 생성 | 기존 내용 삭제 후 쓰기 |
주의:
"w"모드는 기존 내용을 지운다. 중요한 파일에는 바로 사용하지 말고 새 파일 이름으로 먼저 시험한다."binary"라는 모드는 없으며 이진 파일에는"rb"또는"wb"를 사용한다.
파일 사용이 끝나면 파일을 닫아야 한다. with 문을 사용하면 블록을 벗어날 때 파일이 자동으로 닫힌다.
with open("example.txt", "w", encoding="utf-8") as file:
file.write("Hello, file!\n")
file = open(“example.txt”, “w”, encoding=”utf-8”) file.write(“Hello, file!\n”) file.close()
이 강의에서는 파일을 열 때 항상 <code>with open(...)</code> 형식을 사용한다.
# 5. 텍스트 파일 쓰기
## 5.1. 한 줄 쓰기
~~~python
with open("material.txt", "w", encoding="utf-8") as file:
file.write("Aluminum\n")
write()는 줄바꿈을 자동으로 넣지 않는다. 다음 줄로 이동하려면 \n을 직접 써야 한다.
lines = [
"Aluminum\n",
"Iron\n",
"Copper\n",
]
with open("materials.txt", "w", encoding="utf-8") as file:
file.writelines(lines)
with open("materials.txt", "a", encoding="utf-8") as file:
file.write("Titanium\n")
아래의 재료 정보가 text 파일 materials.txt에 저장되어 있다.
| Name | density | strength |
|---|---|---|
| Fe | 7.87 | 200 |
| Al | 2.7 | 90 |
| Ti | 4.51 | 240 |
name density strength
Fe 7.87 200
Al 2.7 90
Ti 4.51 240
with open("materials.txt", "r", encoding="utf-8") as file:
content = file.read()
print(content)
큰 파일은 한 줄씩 처리할 수 있다.
with open("materials.txt", "r", encoding="utf-8") as file:
for line in file:
material = line.strip()
print(material)
strip()은 문자열 양 끝의 줄바꿈(\n)과 공백을 제거한다.
with open("materials.txt", "r", encoding="utf-8") as file:
lines = file.readlines()
print(lines)
1부터 10까지의 정수(integer)를 한 줄에 하나씩 저장해 보자.
with open("numbers.txt", "w", encoding="utf-8") as file:
for number in range(1, 11):
file.write(f"{number}\n")
파일에서 읽은 값도 문자열이므로 계산 전에 숫자로 변환한다.
numbers = []
with open("numbers.txt", "r", encoding="utf-8") as file:
for line in file:
number = int(line.strip())
numbers.append(number)
total = sum(numbers)
average = total / len(numbers)
print(f"합계: {total}")
print(f"평균: {average:.1f}")
다음 성적 데이터 파일은 학생 번호와 점수를 공백으로 구분하여 저장한다. 처음 두 줄은 머리글이므로 건너뛴다.
ID Score
--------------
xxxx5093 14.0
xxxx5298 53.0
먼저 학생 번호와 점수를 읽어 보자.
filename = "score_record_2017_MF_final_analysis.txt"
student_ids = []
scores = []
with open(filename, "r", encoding="utf-8") as file:
next(file)
next(file)
for line in file:
columns = line.split()
if len(columns) != 2:
continue
student_id = columns[0]
score = float(columns[1])
student_ids.append(student_id)
scores.append(score)
링크에서 파일을 내려받아 실행 중인 Notebook과 같은 폴더에 저장한다. 다른 폴더에 저장했다면 실제 위치를 filename에 지정한다. 웹 주소와 컴퓨터에서 Python이 읽는 로컬 파일 경로는 서로 다를 수 있음에 주의한다.
평균, 표준편차, 최고점과 최저점을 계산한다.
average = sum(scores) / len(scores)
squared_sum = 0.0
for score in scores:
squared_sum += (score - average)**2
standard_deviation = (
squared_sum / len(scores)
)**0.5
highest_score = max(scores)
lowest_score = min(scores)
highest_index = scores.index(highest_score)
lowest_index = scores.index(lowest_score)
print(f"평균: {average:.2f}")
print(f"표준편차: {standard_deviation:.2f}")
print(
"최고점:",
student_ids[highest_index],
highest_score,
)
print(
"최저점:",
student_ids[lowest_index],
lowest_score,
)
최고점이 같은 학생이 여러 명이면 index()는 첫 번째 학생만 반환한다. 동점자를 모두 찾는 것은 이후 반복문 연습으로 확장할 수 있다.
pathlib의 glob()을 사용하면 특정 형식의 파일을 찾을 수 있다.
from pathlib import Path
data_folder = Path("score_records")
for path in data_folder.glob("*.txt"):
print(path.name)
다음 압축 파일을 내려받아 여러 성적 파일을 대상으로 실습할 수 있다.
처음에는 파일 이름만 출력하여 선택된 파일이 맞는지 확인한다. 그다음 각 파일을 읽는 함수를 만들어 반복 적용할 수 있다.
다음 인장시험 파일의 파일 이름에서 WZ를 EX로 바꾼다고 하자.
파일 이름 변경은 원래 경로를 바꾸는 작업이므로 먼저 변경 계획만 출력한다.
from pathlib import Path
data_folder = Path("tensile_test_results")
for old_path in data_folder.glob("*WZ*.csv"):
new_name = old_path.name.replace("WZ", "EX")
new_path = old_path.with_name(new_name)
print(f"{old_path.name} -> {new_path.name}")
출력된 대상과 새 이름이 모두 올바른지 확인한 뒤에만 다음 줄을 반복문 안에 추가한다.
old_path.rename(new_path)
안전 확인: 원본 파일이 중요하면 먼저 폴더 전체를 복사해 두고 연습한다. 새 이름의 파일이 이미 존재하는지도 확인해야 한다.
복사하려면 shutil.copy()를 사용한다.
from shutil import copy
copy(old_path, new_path)
지정한 위치에 파일이 없을 때 발생한다.
from pathlib import Path
path = Path("materials.txt")
print(path.exists())
print(path.resolve())
exists()로 파일 존재 여부를 확인하고, resolve()로 Python이 확인하는 전체 경로를 살펴본다.
float()나 int()로 바꿀 수 없는 문자를 숫자로 변환할 때 발생할 수 있다. 빈 줄이나 머리글인지 먼저 확인한다.
파일을 쓸 권한이 없거나 다른 프로그램이 파일을 사용 중일 때 발생할 수 있다. 쓰기 가능한 실습 폴더인지 확인한다.
input()은 항상 문자열을 반환한다.with open(...)으로 열면 자동으로 닫힌다."r"은 읽기, "w"는 새로 쓰기, "a"는 이어 쓰기 모드이다.encoding="utf-8"을 명시하는 것이 좋다.int() 또는 float()로 변환해야 한다.input()이 반환하는 자료형은 무엇인가?
텍스트 파일을 읽기 모드로 여는 표현을 쓰시오.
기존 파일 내용을 지우지 않고 끝에 내용을 추가하려면 어떤 모드를 사용하는가?
다음 코드가 파일에 기록하는 내용을 쓰시오.
with open("value.txt", "w", encoding="utf-8") as file:
file.write("10\n")
file.write("20\n")
파일에서 읽은 문자열 "3.5"를 실수로 변환하는 표현을 쓰시오.
"w" 모드를 기존의 중요한 파일에 사용할 때 주의해야 하는 이유를 쓰시오.
4장 경도 검사 프로젝트를 확장하여, 텍스트 파일에서 경도 데이터를 읽고 검사 보고서를 파일로 저장하는 프로그램을 작성하시오. 이번에는 입력 데이터를 코드 안에 직접 적지 않고, 파일 내용을 바꾸어 같은 프로그램을 재사용한다.
프로그램과 같은 폴더에 hardness_input.txt를 만든다. 각 줄에 시편 이름과 경도 측정값을 공백으로 구분해 적는다. 터미널에서 이 폴더로 이동한 뒤 프로그램을 실행한다. 상대 경로의 파일 이름은 프로그램 파일의 위치가 아니라 현재 작업 폴더를 기준으로 해석된다. 헤더는 없으며, 시편 이름에는 공백이 없다고 가정한다. 빈 줄을 제외한 각 줄은 이름과 숫자 두 항목으로 구성한다. 모든 값은 동일한 경도 척도와 시험 조건에서 얻었다고 가정한다.
A 110
B 130
C 166
D -1
판정은 앞 프로젝트와 같은 가상의 연습 기준을 사용한다.
| 측정값 | 판정 |
|---|---|
| 0 이하 | 잘못된 측정값 |
| 0 초과, 120 미만 | 기준 미달 |
| 120 이상, 150 이하 | 합격 |
| 150 초과 | 기준 초과 |
with open(..., 'r', encoding='utf-8')로 입력 파일을 한 줄씩 읽는다.strip()으로 앞뒤 공백을 제거한다. 빈 줄이면 continue로 건너뛴다.split()으로 이름과 측정값을 나누고, 측정값을 float()로 변환한다.hardness_report.txt에 시편 이름·측정값·판정을 한 줄씩 저장한다.판정은 별도 함수 classify_hardness(value)로 작성해 호출한다. 입력 파일은 변경하지 않는다. 보고서는 'w' 모드로 열어 실행할 때마다 새 결과로 갱신한다. 숫자가 아닌 문자열이나 항목 수가 틀린 줄의 처리는 이번 기본 과제에 포함하지 않는다.
위 입력 파일에 대한 보고서는 다음과 같다. 평균은 소수점 둘째 자리까지 표시한다.
A 110.0 기준 미달
B 130.0 합격
C 166.0 기준 초과
D -1.0 잘못된 측정값
유효값: 3
잘못된 값: 1
합격 시편: 1
평균: 135.33
다음 경우도 확인하시오.
제출물: Python 코드, 입력 파일, 보고서 파일, 확인 사례별 결과, 그리고 ‘파일에서 읽은 문자열을 숫자로 변환하는 이유와 읽기·쓰기 모드의 차이’에 대한 짧은 설명.