이 페이지의 목차
파일에 읽고 쓰는 프로그램
코드 예제: Python · C · 예상 50분
학습 목표
- 파일에 데이터를 저장하고 다시 읽어 오는 프로그램을 작성한다.
- 프로그램을 다시 실행해도 데이터가 남아 있음을 확인한다.
관련 성취기준
- 프그02-06
파일의 개념을 이해하고 지원하는 파일 유형을 사용하여 입력과 출력 과정을 설명할 수 있으며, 파일을 입출력하는 프로그램을 작성할 수 있다.
생각 열기 — 껐다 켜도 남아 있으려면
17차시에서 파일에 쓰고 읽는 법을 배웠다. 그런데 "w" 모드는 열 때마다 내용을 지운다. 메모를 하나씩 쌓아 가려면 어떻게 할까.
쌓아 가는 프로그램
def 저장(줄):
with open("diary.txt", "a", encoding="utf-8") as f:
f.write(줄 + "\n")
def 불러오기():
try:
with open("diary.txt", "r", encoding="utf-8") as f:
return f.read().splitlines()
except FileNotFoundError:
return []
저장("오늘 변수를 배웠다")
저장("내일은 반복문")
for 번호, 줄 in enumerate(불러오기(), 1):
print(번호, 줄)
print("줄 수:", len(불러오기()))1 오늘 변수를 배웠다 2 내일은 반복문 줄 수: 2
#include <stdio.h>
#include <string.h>
void save(const char *text)
{
FILE *f = fopen("diary.txt", "a");
if (f == NULL) return;
fprintf(f, "%s\n", text);
fclose(f);
}
int load_and_print(void)
{
FILE *f = fopen("diary.txt", "r");
if (f == NULL) return 0;
char line[256];
int no = 0;
while (fgets(line, sizeof line, f) != NULL) {
line[strcspn(line, "\n")] = '\0';
printf("%d %s\n", ++no, line);
}
fclose(f);
return no;
}
int main(void)
{
save("오늘 변수를 배웠다");
save("내일은 반복문");
int n = load_and_print();
printf("줄 수: %d\n", n);
return 0;
}1 오늘 변수를 배웠다 2 내일은 반복문 줄 수: 2
두 함수의 겉모습
3단원 3차시의 다섯 칸으로 정리하면 이렇다.
| 함수 | 받는 것 | 돌려주는 것 | 하는 일 | 실패하면 |
|---|---|---|---|---|
저장 |
문자열 한 줄 | 없음 | 파일 끝에 한 줄 덧붙인다 | 열지 못하면 아무것도 하지 않는다 |
불러오기 |
없음 | 문자열 목록 | 파일 전체를 줄 목록으로 돌려준다 | 파일이 없으면 빈 목록 |
「실패하면」 칸이 이 프로그램의 핵심이다. 처음 실행할 때는 파일이 아직 없다. 그때 오류로 멈추면 프로그램을 한 번도 쓸 수 없다.
이어 쓰기가 만드는 차이
같은 프로그램을 두 번 실행하면 어떻게 될까.
| 실행 | "a" 모드 (지금) |
"w" 모드였다면 |
|---|---|---|
| 1회 | 2줄 | 2줄 |
| 2회 | 4줄 | 2줄 (앞의 것이 지워짐) |
| 3회 | 6줄 | 2줄 |
"a" 는 앞의 것을 지키고 덧붙인다. 프로그램을 껐다 켜도 자료가 남는다는 것이 이 모드에서 나온다.
2단원의 도구가 여기 다 들어 있다
이 프로그램 하나에 2단원에서 배운 것이 거의 다 쓰였다.
| 차시 | 무엇이 쓰였나 |
|---|---|
| 1·2차시 변수와 자료형 | 문자열을 다루고 개수를 정수로 센다 |
| 3차시 문자열 | 줄 끝의 줄바꿈을 잘라 낸다 |
| 4차시 리스트 | 읽은 줄들을 목록으로 담아 돌려준다 |
| 5차시 출력 형식 | 번호와 내용을 나란히 찍는다 |
| 10차시 반복 | 줄마다 되풀이해 찍는다 |
| 13~16차시 함수 | 저장과 불러오기를 나눠 만들고 이름으로 부른다 |
| 17차시 파일 | 모드를 골라 열고 닫는다 |
2단원의 도구만으로도 쓸 만한 프로그램이 된다. 단원 개요에 적힌 그 말이 이 자리에서 확인된다.
활동
간단 메모장 — 입력한 내용을 파일에 남기고 다시 불러오기
약 40분1단계 — 겉모습을 먼저 적는다 (5분)
만들 함수의 다섯 칸을 채운다. 「실패하면」 칸을 비우지 않는다.
| 함수 | 받는 것 | 돌려주는 것 | 하는 일 | 실패하면 |
|---|---|---|---|---|
2단계 — 입력으로 받게 만든다 (10분)
지금 예제는 메모 내용이 코드에 박혀 있다. 6차시에서 배운 입력으로 받게 바꾼다.
- 여러 줄을 받으려면 반복이 필요하다.
for인가while인가? 왜 그런지 근거를 적는다 (12차시). - 「빈 줄을 넣으면 끝낸다」는 요구를 넣으려면 무엇을 쓰는가?
3단계 — 전산실에서 두 번 실행한다 (10분)
이 단계는 실행기가 아니라 설치형 환경에서 한다.
| 확인할 것 | 결과 |
|---|---|
| 1회 실행 뒤 파일의 줄 수 | |
| 2회 실행 뒤 파일의 줄 수 | |
diary.txt 가 어느 폴더에 생겼나 |
|
| 메모장으로 열어 보니 한글이 보이나 |
- 브라우저 실행기에서는 왜 줄 수가 늘지 않았는가?
- 모드를
"w"로 바꾸면 2회 실행 뒤 줄 수가 어떻게 되는가? 먼저 예상한 뒤 확인한다.
4단계 — 기능을 하나 고른다 (10분)
아래 중 하나를 골라 만든다.
| 기능 | 무엇이 더 필요한가 |
|---|---|
| 메모마다 번호를 파일에도 남긴다 | 불러온 개수를 세어 다음 번호를 만든다 |
| 특정 낱말이 든 메모만 찾아 보여 준다 | 반복 안의 선택, 문자열 찾기 |
| 마지막 메모만 지운다 | 전부 읽어 마지막을 뺀 뒤 “w” 로 다시 쓴다 |
- 마지막 기능을 고르면
"w"를 쓰는 위험을 어떻게 다룰 것인가? 3단원 8차시의 결함 보고서 형식으로 「무엇이 잘못될 수 있는가」를 적어 본다.
5단계 — 테스트 사례를 적는다 (5분)
3단원 7차시의 네 갈래로 사례를 만든다.
| 갈래 | 넣을 값 | 기대 결과 |
|---|---|---|
| 정상값 | ||
| 경계값 (빈 문자열) | ||
| 파일이 없는 상태 | ||
| 아주 긴 줄 |
개인정보 주의 — 메모에 실제 친구 이름이나 연락처를 넣지 않는다. 파일은 남고, 남은 파일은 옮겨진다.
개념 확인 문제
보기를 누르면 바로 채점된다. 틀려도 해설을 읽으면 된다.
프로그램을 껐다 켜도 자료가 남게 하려면 어느 모드로 파일을 여는가?프그02-06
불러오기 가 파일이 없을 때 빈 목록을 돌려주는 것이 나은 까닭은?프그02-06
브라우저 실행기에서 [실행]을 여러 번 눌러도 파일의 줄 수가 늘지 않는 까닭은?프그02-06
C의 load_and_print 가 fopen 실패 시 0 을 돌려주는 것은 Python의 무엇에 해당하는가?프그02-06
「마지막 메모만 지운다」 기능을 만들 때 「w」 모드를 쓰는 것이 위험한 까닭은?프그02-06
이 차시의 메모장 프로그램에 쓰이지 않은 2단원 내용은?프그02-06
더 알아보기
실무지우기 전에 임시 파일에 쓴다
활동 4단계의 「마지막 메모 지우기」에는 함정이 있다. 전부 읽어 목록을 만들고, "w" 로 열어 다시 쓰는 방식이다. "w" 로 열는 순간 파일이 비워진다. 그 뒤 쓰는 도중에 프로그램이 죽거나 전원이 꺼지면 자료를 통째로 잃는다.
실무에서 쓰는 방법은 이렇다. 임시 파일에 새 내용을 먼저 다 쓰고, 성공한 뒤에 원래 파일과 이름을 바꾼다. 도중에 실패하면 원래 파일이 그대로 남아 있다. 이름을 바꾸는 일은 대개 한순간에 끝나므로 중간 상태가 남지 않는다.
문서 편집 프로그램이 저장할 때 실제로 이렇게 한다. 자료를 다루는 프로그램에서 「지우기 전에 안전한 사본」은 기본이다.
심화파일이 곧 프로그램 사이의 다리
17차시 「더 알아보기」에서 CSV를 봤다. 파일의 진짜 쓸모가 여기 있다 — 다른 프로그램과 자료를 주고받는 통로다.
우리 프로그램이 성적을 CSV로 남기면 엑셀에서 열어 그래프를 그릴 수 있다. 반대로 엑셀에서 CSV로 내보낸 것을 우리 프로그램이 읽을 수도 있다. 두 프로그램은 서로를 전혀 모르고, 파일 형식만 약속되어 있으면 된다.
3단원 3차시에서 부품끼리 주고받을 것을 못 박은 것과 같은 이야기다. 형식이 곧 약속이고, 그 약속이 지켜지면 안쪽은 서로 몰라도 된다.
심화여러 프로그램이 같은 파일을 만지면
두 프로그램이 같은 파일에 동시에 쓰면 어떻게 될까. 내용이 섞이거나 한쪽이 쓴 것이 사라질 수 있다. 1단원 9차시에서 다룬 덮어쓰기 문제가 파일 수준에서 일어나는 것이다.
그래서 운영체제는 파일을 잠그는 장치를 제공하고, 여러 사람이 동시에 자료를 다뤄야 하는 곳에서는 파일 대신 데이터베이스를 쓴다. 데이터베이스는 이런 충돌을 다루는 것이 본업인 프로그램이다.
지금 단계에서는 한 번에 한 프로그램만 그 파일을 만진다고 전제하고 만들면 된다. 다만 그것이 전제라는 사실은 알아 두는 편이 좋다 — 3단원 2차시의 비기능 요구에 적어 둘 만한 내용이다.
이어지는 학습
이 차시를 이해하려면 다음을 먼저 알아야 한다.
- 17차시의 파일 열기와 닫기 — 프로그래밍 프그02-06
교과서에서 찾기
| 교과서 | 해당 위치 | 쪽수 |
|---|---|---|
| 성림출판(Python) | 프로그래밍의 기초 › 06 파일 처리 | 190쪽 |
| 씨마스커뮤니케이션(Python) | 프로그래밍 기초 › 6 파일 처리 | 162쪽 |
| 삼양미디어(Python) | 프로그래밍의 기초 › 05 파일 처리 | 148쪽 |
| 삼양미디어(C) | 프로그래밍의 기초 › 05 파일 처리 | 152쪽 |
| 씨마스(C) | C 프로그래밍의 기초 › 9 파일 입출력 | 164쪽 |
| 웅보출판사(C) | 프로그래밍의 기초 › Chapter 07 파일 처리 | 175쪽 |