파일의기본개념과특징을이해한다. 파일처리과정을이해한다. 형식을지정한파일입출력 fscanf/fprintf를배운다. 문자단위입출력 fgetc/fputc를배운다. 문자열단위입출력 fgets/fputs를배운다. 이진파일입출력 fread/fwrite를배운다. 임의접근을통한파일입출력을위한 fseek, rewind, ftell을배운다.
12.0 개요 p.592 표준입출력과파일입출력 키보드 ( 표준입력장치 ) C 프로그램 age 변수 20 input.txt 20 모니터 ( 표준출력장치 ) output.txt 나이 : 20 세 표준입출력의문제점 키보드입력 : 실행마다똑같은데이터를입력 모니터출력 : 실행결과창스크롤링, 결과창을닫으면출력내용이사라짐 해결 : 데이터를저장한파일로부터입력을받고결과를파일로저장하기 2
12.0 개요 p.594 그림 12-4 표준입출력장치를통한입출력과파일을통한입출력예 키보드 ( 표준입력장치 ) 입력 scanf( %d, &age) C 프로그램 age 변수 20 출력 printf( 나이 :%d 세, age) 모니터 ( 표준출력장치 ) 나이 : 20 세 fp1에연결된파일파일에서읽기 20 fscanf(fp1, %d, &age) C 프로그램 age 변수 20 fp2에연결된파일파일에쓰기나이 : 20세 fprintf(fp2, 나이 :%d세, age) 3
12.1 파일이란? p.593 파일 (file) 보조기억장치에저장된물리적인데이터집합체 저장된내용의용도에따라프로그램파일과데이터파일로구분 그림 12-2 프로그램파일 한글프로그램 포토샵프로그램 실험관리프로그램 소개서.hwp 과제.hwp 꽃.jpg 풍경.jpg 실험값.txt 분석결과.txt 데이터파일 4
12.2 파일처리과정 p.595 파일입출력네단계 : 그림 12-6 파일입력프로그램 FILE * fp; : fp = fopen( data.txt", r"); : fscanf(fp, "%d", &age); fscanf(fp, "%d", &height); : fclose(fp1); 1 파일포인터선언 2 파일열기 3 파일읽기 ( 파일에서읽은데이터를변수에저장 ) 4 파일닫기 키보드입력프로그램 : scanf("%d", &age); scanf("%d", &height); : 프로그램변수 age 20 height fp 에연결된 data.txt 파일 20 170 fp 프로그램변수 age 20 height 키보드 20 170 170 170 5
12.2.1 파일포인터선언하기 p.596 파일포인터선언과파일열기 파일포인터가할당되어있는파일에대해서만읽기 / 쓰기가가능 파일열기를통해파일포인터를파일에연결해야함 형식 : 파일명 파일을열기 FILE * 파일포인터명 ; 파일포인터명 = fopen( 파일명, 모드 ); 파일명 의파일을 모드 에맞게열며파일포인터가열린파일을가리키게된다. r : 읽기전용, r+ 읽기 / 쓰기용 파일명 의파일이없다면에러로 NULL 반환 w : 쓰기전용, w+ 읽기 / 쓰기용 파일내용을모두지움, 파일명 의파일이없다면새로만듬 a : 추가전용, a+ 읽기 / 쓰기추가용 파일의끝에데이터를추가, 파일명 파일이없다면새로만듬 6
12.2.2 파일열기 : fopen 함수 p.597 파일포인터선언과파일열기예 FILE *fp; fp = fopen("data.txt", "w"); // 선언과동시에파일열기 FILE *fp = fopen( data.txt, w ); fp data.txt 파일의정보를가진 FILE 구조체 data.txt 파일 쓰기모드로열린빈파일 fp data.txt 파일 쓰기모드로열린빈파일 파일의위치 단순화하여 fp 가 data.txt 파일을가리킨다고생각하는것이편리 특별히위치를지정하지않으면프로젝트폴더에파일이생성되며읽기용파일이라면미리프로젝트폴더에저장되어있어야함 프로젝트폴더에있지않다면 C:\\file\\age.txt 와같이절대경로를명시해야함 7
12.2.2 파일열기 : fopen 함수 p.597 파일열기실패처리 fopen 함수가실패시 NULL 이반환됨 열기에러처리코드의예 지정한이름의파일이존재하지않는경우의에러처리코드 FILE *fp; fp = fopen("data.txt", "r"); if (fp == NULL) { printf(" 지정한이름의파일을열수없습니다. \n"); exit(1); } 8
12.2.3 파일입출력함수 p.599 파일입출력함수 12.3 에서자세히소개 9
12.2.4 파일닫기 : fclose 함수 p.599 파일닫기 프로그램종료전에열린파일들을닫아야함 닫은파일에연결된파일포인터는새로운파일열기에사용가능 형식 예 fclose( 파일포인터명 ); 현재파일포인터에연결된파일이닫기며파일포인터와의연결이해제됨 FILE *fp; fp = fopen("data.txt", "w"); : // 파일에자료쓰기 fclose(fp); // 파일닫기 : fp = fopen( result.txt", "w"); // 파일포인터재사용 10
12.3.1 형식을지정한파일출력 : fprintf 함수 p.591 fprintf 함수 지정한형식에맞추어데이터를파일로출력 형식 printf 를사용한모니터로의출력과똑같은내용의결과를얻음 fprintf( 파일포인터명, 변환명세포함한형식문자열, 변수명 ); 상수또는식도가능 변수값이 형식문자열 에맞게변환되여파일포인터에연결된파일에기록됨 printf 함수사용한모니터출력결과그대로파일에기록됨 11
12.3.2 형식을지정한파일출력 : fprintf 함수 p.591 예 ) FILE *fp = fopen( data.txt, r ); age = 20; fprintf(fp, " 나이 : %d세", age); 나이 : 20 세 fp C 프로그램 age 변수 20 stdout 12
12-2 회원 5 명의나이정보를파일에저장하기 p.602 1 #include <stdio.h> // fopen, fprintf, fclose 함수를위한헤더파일 2 #include <stdlib.h> // exit 함수를위한헤더파일 3 #define SIZE 5 // 회원수 4 5 int main() 6 { 7 FILE *fp; // 파일포인터선언 8 char *f_name = "age.txt"; // 파일명, char f_name[20]="age.txt"; 도가능 9 int age, i; 10 11 fp = fopen(f_name, "w"); // fp = fopen("age.txt", "w") 도가능 12 13 if (fp == NULL) // 파일열기에러처리 14 { 15 printf(" %s 파일열기에러! \n", f_name); 16 exit(1); 17 } 19 printf(" 회원 %d 명의나이를입력하면파일로저장합니다.\n", SIZE); 13
12-2 회원 5 명의나이정보를파일에저장하기 p.602 21 for (i=0; i<size; i++) // SIZE 명의나이를키보드에서입력받아파일에쓰기 22 { 23 printf("%2d 번회원의나이는? ", i+1); 24 scanf("%d", &age); // 키보드에서회원의나이를입력받기 25 26 fprintf(fp, "%d\n", age); // age 의값을 fp 에연결된파일에쓰기 27 } 28 29 fclose(fp); // fp 에연결된 age.txt 파일을닫고연결을끊기 30 printf(" 회원 %d 명의나이를 %s 파일에저장했습니다.\n", SIZE, f_name); 31 32 return 0; 33 } age.txt 파일의내용 실행결과회원 5명의나이를입력하면파일로저장합니다. 1번회원의나이는? 20 2번회원의나이는? 23 3번회원의나이는? 25 4번회원의나이는? 21 5번회원의나이는? 20 회원 5명의나이를 age.txt 파일에저장했습니다 20 23 25 21 20 14
프로그램 12-2 회원 5 명의나이정보를파일에저장하기 p.602 분석 키보드로입력받은나이를파일에쓰는과정 (24, 26행 ) 을 5번반복하면파일에 5개의나이가저장됨 C 프로그램 fp age.txt 파일 키보드 입력 scanf( %d, &age) age 변수 20 출력 fprintf(fp, %d\n, age) 20 15
12.3.2 형식을지정한파일입력 : fscanf 함수 p.603 fscanf 함수 파일의데이터를변환명세로지정한형식에맞게읽어서변수에저장 scanf 의키보드자료입력과똑같은내용이파일에기록되어있어야함 형식 scanf( 파일포인터명, 변환명세, & 변수명 ) 파일포인터가가리키는파일에서변환명세맞게데이터를읽어서변수에저장 읽기실패또는파일의끝에도달했다면 EF를반환 16
12.3.2 형식을지정한파일입력 : fscanf 함수 p.603 예 ) FILE *fp = fopen("read.txt"); fscanf(fp, "%d", &age); fscanf(fp, "%d", &height); fp read.txt 파일 20 파일에서읽기 fscanf(fp, %d, &age); C 프로그램 20 age 변수 170 fscanf(fp, %d, &height); 170 height 변수 17
12-3 age.txt 파일의나이정보를화면에출력하기 p.604 1 #include <stdio.h> // fopen, fscanf, fclose 함수를위한헤더파일 2 #include <stdlib.h> // exit 함수를위한헤더파일 3 #define SIZE 5 // 회원수 4 5 int main() 6 { 7 FILE *fp; // 파일포인터선언 8 char *f_name = "age.txt"; // 파일명, char f_name[20]="age.txt"; 도가능 9 int age, i; 10 11 fp = fopen(f_name, "r"); // f_name 이름의파일을읽기용으로열기 12 13 if (fp == NULL) // 파일열기에러처리 14 { 15 printf(" %s 파일을열수없습니다. \n", f_name); 16 exit(1); 17 } 18
12-3 age.txt 파일의나이정보를화면에출력하기 p.604 19 for (i=0; i<size; i++) // 파일의나이를 SIZE 개읽어모니터에출력하기 20 { 21 // fp 에연결된파일에서정수한개를읽어 age 에저장하기 22 fscanf(fp, "%d", &age); 23 24 // age 에저장된나이를모니터에출력하기 25 printf("%2d 번회원의나이는 %d 세 \n", i+1, age); 26 } 27 28 fclose(fp); // fp 에연결된 age.txt 파일을닫고연결을끊기 30 return 0; 31 } 실행결과 1번회원의나이는 20세 2번회원의나이는 23세 3번회원의나이는 25세 4번회원의나이는 21세 5번회원의나이는 20세 age.txt 파일의내용 20 23 25 21 20 19
fprintf 와 fscanf 의주의점 p.601 주의 p.601 여러값을한꺼번에파일에쓸때공백문자 ( 빈칸, 탭키, 엔터키 ) 넣기 age = 20; height = 170; 공백문자가없다. fprint(fp, "%d%d\n", age, height); 20170 이후이파일을읽기용으로연후 fscanf(fp, %d%d, &age, &height); 를사용한다면? 20170 이 age 에저장되고 height 에는데이터가입력되지않음 20 과 170 사이에공백문자를넣어둬야한다. 20
fprintf 와 fscanf 의주의점 p.603 주의 p.603 scanf와마찬가지로변환명세에주의 일반문자사용불가 필드폭은생략 변환명세끝에빈칸이나 \n 넣지말기 fscanf(fp, " 키 :%5d ", &height); 일반문자는불가능 빈칸또는 \n 을넣으면데이터를한개더읽게됨 필드폭을사용않는것이더안전 21
12.3.3 파일의추가 p.605 추가모드의필요성 쓰기모드는기존의파일내용을모두지우고새로쓰기를함 이전실행결과와함께새실행결과도같은파일에저장하고싶을때는추가모드로열어야함 [ 프로그램 12-4] [ 프로그램 12-2] 에서만든 age.txt 파일에 n 명의나이를추가하는프로그램 파일작성두가지방법 프로그램을통한실행결과로만들기 프로그램에사용할데이터를미리일반편집기를이용하여파일로만들기 목적에따라두방법중선태가능 [ 프로그램 12-2] 를실행하지않고 age.txt 파일을메모장또는비주얼스튜디오에서직접만든후 [ 프로그램 12-4] 를실행해도됨 22
12-4 age.txt 파일에 n 명의나이추가하기 p.605 1 #include <stdio.h> // fopen, fprintf, fclose 함수를위한헤더파일 2 #include <stdlib.h> // exit 함수를위한헤더파일 3 4 int main() 5 { 6 FILE *fp; // 파일포인터선언 7 char *f_name = "age.txt"; // 파일명, char f_name[20]="age.txt"; 도가능 8 int age, i, n; 9 추가모드 10 fp = fopen(f_name, "a"); // f_name 이름의파일을추가용으로열기 11 12 if (fp == NULL) // 파일열기에러처리 13 { 14 printf(" %s 파일열기에러! \n", f_name); exit(1); 15 } 23
12-4 age.txt 파일에 n 명의나이추가하기 p.605 17 printf(" 회원의나이를입력하면 %s 파일에추가합니다.\n", f_name); 18 printf(" 추가할회원의수는? "); 19 scanf("%d", &n); // 파일에추가할회원나이개수를입력 20 21 // n 명의나이를키보드에서입력받아파일에추가하기 22 for (i=0; i<n; i++) 23 { 24 printf(" 회원의나이는? "); 25 scanf("%d", &age); // 키보드에서회원의나이를입력 26 27 fprintf(fp, "%d\n", age); // age 에저장된나이를 fp 에연결된파일에쓰기 28 } 29 fclose(fp); 30 printf(" 회원 %d 명의나이를 %s 파일에추가했습니다.\n", n, f_name); 31 32 return 0; 33 } 24
프로그램 12-4 age.txt 파일에 n 명의나이추가하기 p.605 분석 실행전 age.txt 파일의내용 20 23 25 21 20 실행결과 회원의나이를입력하면 age.txt 파일에추가합니다. 추가할회원의수는? 3 회원의나이는? 29 회원의나이는? 31 회원의나이는? 27 회원 3 명의나이를 age.txt 파일에추가했습니다. 실행후 age.txt 파일의내용 20 23 25 21 20 29 31 27 25
12.3.4 파일의끝확인하기 p.607 파일에저장된레코드 ( 데이터 ) 수를정확히모른다면? 파일의끝을확인하여파일읽기를중단하는방법을사용해야한다. 대표적방법두가지 1. feof 함수이용하기 파일의끝을지나제대로읽기를못했다면파일에서읽기를그만하기 2. fscanf 함수의반환값활용하기 파일의끝에도착하거나에러가발생하여 EF 를반환하지않았다면읽은데이터를사용하고그렇지않다면읽기를그만하기 26
12.3.4 파일의끝확인하기 p.607 feof 함수 feof( 파일포인터명 ) 파일포인터에연결된파일의끝을지나갔다면 0이아닌값 ( 참 ) 을, 아직파일의끝을지나지않았다면 0( 거짓 ) 을반환 필독파일의끝 ( 문자 ) 에도달했을때가아니라파일끝 ( 문자 ) 을지나갔을때 0 이아닌값 ( 참 ) 을반환함 제대로이해하지못했다면 [ 프로그램 12-5] 와같이잘못된결과를초래할수있으므로주의해야한다. 예 ) fp 에연결된파일의끝을지났다면파일을닫기 if (feof(fp)) fclose(fp); 27
12.3.4 파일의끝확인하기 p.607 [ 프로그램 12-6] 문제 분석 입력 : [ 프로그램 12-4] 의결과파일인 age.txt 출력 : age.txt 파일에저장된모든나이를모니터에표시하기 프로그램실행결과로만들어진파일에저장된데이터수는파일을확인하지않는한알수없다. feof 함수를이용하여파일끝을지나지않은한읽기를계속하여해결 28
12-6 파일의끝을확인하는 feof 함수의정확한사용예 p.610 1 #include <stdio.h> // fopen, fscanf, fclose, feof 함수를위한헤더파일 2 #include <stdlib.h> // exit 함수를위한헤더파일 4 int main() 5 { 6 FILE *fp; // 파일포인터선언 7 int age; 8 9 fp = fopen("age.txt", "r"); // 파일을읽기모드로열기 : 15 // 파일에저장된모든나이를읽어서모니터에출력하기 16 fscanf(fp, "%d", &age); // 일단파일에서정수 ( 나이 ) 읽기를시도 17 while (!feof(fp)) // 아직파일의끝을지나지않았다면반복하기 18 { 19 printf("%2d \n", age); // 방금파일에서읽은정수 ( 나이 ) 를모니터로출력하기 20 fscanf(fp, "%d", &age); // 파일에서다음정수 ( 나이 ) 읽기를시도 21 } 22 23 fclose(fp); // fp 에연결된파일닫기 age.txt 파일의내용 25 return 0; 20 26 } 23 25 29
12.3.4 파일의끝확인하기 p.610 fscanf 함수의반환값활용하기 fscanf는파일의끝에도착하거나에러가나면 EF를반환한다. 일단파일에서읽기를시도후, fscanf의반환값을확인하여읽기의성공여부를확인가능 아주단순하여프로그래머들이선호 [ 프로그램 12-6] : 9 fp = fopen("age.txt", "r"); : 15 // 파일에저장된모든나이를읽어서모니터에출력하기 16 fscanf(fp, "%d", &age); 17 while (!feof(fp)) 18 { 19 printf("%2d \n", age); 20 fscanf(fp, "%d", &age); 21 } 22 23 fclose(fp); // fp 에연결된파일닫기 // 일단파일에서정수를한개읽어온후 // 성공했다면출력하기를반복하기 while (fscanf(fp, "%d", &age)!= EF) { printf("%2d \n",age); } age.txt 파일의내용 20 23 25 30
12.6.1 판매실적우수자파일만들기 p.623 문제 : 판매실적우수자파일만들기 입력 : 사원번호, 자동차판매실적이저장된 sales_report.txt 파일 출력 : 판매실적이 30 보다큰사원번호, 판매실적을저장한 good.txt 파일 sales_report.txt 파일 분석 1203 25 1102 35 1103 21 1205 29 1105 32 1202 40 1207 25 1112 27 1113 52 1212 27 sales_report.txt 파일만들기 [ 프로그램 12-13] 판매실적우수자 ------------------- 사원번호판매수 ------------------- 1102 35 대 1105 32 대 1202 40 대 1113 52 대 ------------------- 자료를읽을순서에맞게자료형에맞게만들어야하며마지막자료뒤에도엔터키를입력하는것을잊지않는다. good.txt 파일 31
12-13 사원정보파일에서판매실적우수자명단파일만들기 p.623 1 #include <stdio.h> // fopen, fscanf, fprintf, fclose, EF, printf 의헤더파일 2 #include <stdlib.h> // exit 함수를위한헤더파일 3 4 int main() 5 { 6 int no, sales; 7 FILE *fpr, *fpw; // 읽기용, 쓰기용파일포인터선언 8 9 fpr = fopen("sales_report.txt", "r"); // 판매실적파일을읽기용으로열기 10 if (fpr == NULL) // 파일열기에러처리 11 { printf(" 파일열기에러! \n"); exit(1); } 14 15 fpw = fopen("good.txt", "w"); // 우수자명단파일을쓰기용으로열기 16 if (fpw == NULL) // 파일열기에러처리 17 { printf(" 파일열기에러! \n"); exit(1); } 20 21 // 출력제목을파일에쓰기 22 fprintf(fpw, " 판매실적우수자 \n\n"); 23 fprintf(fpw, " ------------------- \n"); 24 fprintf(fpw, " 사원번호판매수 \n"); 25 fprintf(fpw, " ------------------- \n"); 32
12-13 사원정보파일에서판매실적우수자명단파일만들기 p.623 27 // 파일에서읽기를성공했다면판매수가 30 보다클때만우수자명단파일에저장하기 28 while (fscanf(fpr, "%d %d", &no, &sales)!= EF) 29 { 파일에저장된레코드수를모를 30 if (sales > 30) 때파일읽기가제대로되었을 31 { 때만 while 본체실행하기 32 fprintf(fpw, " %5d %5d 대 \n", no, sales); 33 // printf(" %5d %5d 대 \n", no, sales); 모니터결과확인용 34 } 35 } 36 fprintf(fpw, " ------------------- \n"); 37 38 fclose(fpr); fclose(fpw); // 파일닫기 39 printf(" 우수자명단파일을저장했습니다. \n"); 40 41 return 0; sales_report.txt 42 } fpr 1203 25 1102 35 1103 21 1205 29 1105 32 1202 40 : : no 1102 sales 35 good.txt 파일 판매실적우수자 ------------------- 사원번호판매수 ------------------- 1102 35 대 33
12-13 사원정보파일에서판매실적우수자명단파일만들기 p.623 sales_report.txt 파일의내용 1203 25 1102 35 1103 21 1205 29 1105 32 1202 40 1207 25 1112 27 1113 52 1212 27 [ 프로그램 12-13] good.txt 파일의내용판매실적우수자 ------------------- 사원번호판매수 ------------------- 1102 35 대 1105 32 대 1202 40 대 1113 52 대 ------------------- 34
프로그램 12-13 판매실적우수자명단파일만들기 p.623 만일판매실적을내림차순으로정렬하여모니터로출력하려면? 정렬을하기위해서는모든자료가배열에저장되어야하므로파일에서읽은자료를다음그림과같이배열에저장해야한다. sales_report.txt 파일의내용 1203 25 1102 35 1103 21 1205 29 1105 32 1202 40 1207 25 1112 27 1113 52 1212 27 int no[10]; 1203 1102 1103 : 1212 int sales[10]; 25 35 21 : 27 배열을정렬후모니터로출력하기 (printf) 또는파일로출력하기 (fprinf) 35
파일처리의팁 파일처리의팁 22~36 행 1. 파일로출력하는 fprintf 부분을 39 행처럼모두 printf 함수로작성한후 2. 결과가제대로나오면 36행처럼 fprintf 함수로바꾸는것도결과를쉽게확하는방법예 ) 32행을 printf(" %5d %5d대 \n", no, sales); 로작성후 fprintf(fpw, " %5d %5d 대 \n", no, sales); 로수정하기 모니터와파일출력을둘다하기 printf 함수로출력하는부분을모두복사하여 fprintf 로변경함으로써모니터로도결과를출력하고파일로도출력가능 32 fprintf(fpw, " %5d %5d 대 \n", no, sales); 33 printf(" %5d %5d 대 \n", no, sales); 36
12.4.1 문자단위로파일에쓰기 : fputc 함수 p.615 fputc 함수 파일에한문자씩출력 형식 fputc( 문자, 파일포인터명 ) 문자를파일포인터가가리키는파일에씀 fputc( 정수, 파일포인터변수명 ) 예 ASCII 코드값이정수에해당하는문자한개를파일에씀 fputc(67, fp); fp에연결된파일에 'C' 를쓴다. ch = 'A'; fputc(ch, fp); fp에연결된파일에 'A' 를쓴다. 37
12.4.2 문자단위로파일읽기 : fgetc 함수 p.616 fgetc 함수 파일에서문자한개를읽어반환 형식 fgetc( 파일포인터명 ) 파일포인터명에연결된파일에서문자한개를읽어서반환 반환형은 int형 ( 문자의 ASCII 코드값 ) 읽기에러 / 파일의끝도달 매크로상수 EF(-1에해당 ) 반환 예 ) char ch; FILE *fp = feopn("data.txt", "r"); ch = fgetc(fp); data.txt 파일에서문자한개를읽은후 ch에저장 38
12.4.3 프로그램예 : 파일복사프로그램 p.618 문제 [ 프로그램 12-9], [ 프로그램 12-10] 을이용기존파일을복사하기 입력 : 사용자가복사하고싶은원본파일명과복사본의파일명 출력 : 원본파일과동일한복사본파일 분석 [ 프로그램 12-10] 과같이원본파일에서한문자를읽은후 [ 프로그램 12-9] 와같이복사본파일에읽은문자를쓰기 fp1 fp2 원본파일 C 프로그램 복사본파일 Hello. Hi. How are you? 파일에서읽기 ch = fgetc(fp1) ch 변수 H 파일에쓰기 fputc(ch, fp2); H 39
12-11 파일복사프로그램 p.618 1 #include <stdio.h> // fgetc, fputc, fopen, fclose 함수를위한헤더파일 2 #include <stdlib.h> // exit 함수를위한헤더파일 4 int main() 5 { 6 FILE *fp1, *fp2; // 원본파일과복사본파일에대한파일포인터 7 char f_name1[30], f_name2[30], ch; // 원본파일명, 복사본파일명 9 printf(" 파일을복사합니다.\n"); 10 11 // 원본파일을읽기모드로열기 12 printf(" 원본파일명 : "); gets(f_name1); 13 fp1 = fopen(f_name1, "r"); 14 if (fp1 == NULL) 15 { 16 printf(" %s 란파일이없습니다. \n", f_name1); exit(1); 17 } 19 // 복사본파일을쓰기모드로열기 20 printf(" 복사본파일명 : "); gets(f_name2); 21 fp2 = fopen(f_name2, "w"); 22 if (fp2 == NULL) 23 { 24 printf(" %s 란파일이없습니다. \n", f_name2); exit(1); 25 } 40
12-11 파일복사프로그램 p.618 27 // 파일의끝에도달하지않아서 ch 에저장된값이 EF 가아니라면복사본에쓰기를반복 28 while ((ch = fgetc(fp1))!= EF) 29 fputc(ch, fp2); // 복사본파일에읽은문자쓰기 30 31 fclose(fp1); fclose(fp2); 32 printf(" 원본 %s 를복사한복사본 %s 가저장되었습니다. \n", f_name1, f_name2); 33 34 return 0; 35 } ch = fgetc(fp1); // 원본파일에서문자한개읽기 while (!feof(fp1)) // 파일의끝을지나지않았다면반복하기 { fputc(ch, fp2); // 읽은문자를복사본파일에쓰기 ch = fgetc(fp1); } 41
12.5.1 문자열단위입출력 : fgets, fputs 함수 p.620 텍스트파일입출력에사용 fputs 함수 문자열단위의파일쓰기 puts 와달리파일에쓸때자동으로개행문자를넣지않음에주의 이곳에저장된문자열을파일포인터에연결된파일에쓴다. fputs( 문자열주소, 파일포인터명 ) 문자열의끝을나타내는널문자및개행문자가자동으로들어가지않음 성공하면출력한바이트수를반환, 실패하면 EF 반환 42
12.5.1 문자열단위입출력 : fgets, fputs 함수 p.620 fgets 함수 문자열단위의파일쓰기 puts 와달리파일에쓸때자동으로개행문자를넣지않음에주의 파일에서읽은문자열을저장 fgets( 문자열주소, 최대입력문자수, 파일포인터명 )) ( 최대문자수 - 1) 개의문자 + 널문자 (\0) 를지정한문자열주소부터저장 gets 와달리개행문자도포함해서계속읽음 if ( 최대문자수만큼읽기전개행문자 (\n) 를읽음 ) 읽기중단, 널문자 (\0) 합친문자열을저장 읽는중파일끝에도달또는에러발생 NULL 포인터반환 43
12.5.1 문자열단위입출력 : fgets, fputs 함수 p.620 예 ) char string1[20], string2[20], string3[20]; FILE *fp = fopen("address.txt", "r"); fgets(string1, 20, fp); fgets(string2, 20, fp); fgets(string3, 20, fp); 44
12.5.2 프로그램예 : 주소록만들기 p.621 [ 프로그램 12-12] 입력 : 학생 5 명의연락처를한행씩입력 출력 : 주소록파일 address.txt 만든후주소록파일의내용을화면에표시 실행결과 이름전화번호주소입력후엔터키를누르세요.(5명) 1. 나태희 010-5757-2828 서울동작구 2. 유현빈 010-2425-7979 서울영등포구 3. 나원빈 010-8282-1472 대구북구 4. 문건영 010-3344-8485 대전동구 5. 소지법 010-7889-5229 부산해운대구 >> 주소록목록 << 나태희 010-5757-2828 서울동작구 유현빈 010-2425-7979 서울영등포구 나원빈 010-8282-1472 대구북구 문건영 010-3344-8485 대전동구 소지법 010-7889-5229 부산해운대구 22행 gets(info); 23행 fputs(info, fp); 의결과 address.txt 파일의내용 나태희 010-5757-2828 서울동작구 유현빈 010-2425-7979 서울영등포구 나원빈 010-8282-1472 대구북구 문건영 010-3344-8485 대전동구 소지법 010-7889-5229 부산해운대구 39 행 fgets(info, 80, fp); 38 행 printf( %s, info); 의결과 24 행 fputs( \n, fp); 의결과 45
12-12 문자열단위의파일입출력예 p.621 1 #include <stdio.h> // fputs, fgets 함수를위한헤더파일 2 #include <stdlib.h> // exit 함수를위한헤더파일 3 #define SIZE 5 5 int main() 6 { 7 char f_name[20] = "address.txt"; 8 char info[80]; 10 FILE *fp = fopen(f_name, "w"); // 주소를저장할파일열기 11 int i; 12 13 if (fp == NULL) // 파일열기에러처리 14 { printf(" 파일열기에러! \n"); exit(1); } 17 18 printf(" 이름전화번호주소입력후엔터키를누르세요.(%d 명 ) \n", SIZE); 19 for (i=0; i<size; i++) 20 { 21 printf("%d. ", i+1); 22 gets(info); // 키보드로한행씩입력받는다. 23 fputs(info, fp); // 입력받은문자열을파일에쓰기 24 fputs("\n", fp); // 문자열뒤에개행문자쓰기 25 } 26 fclose(fp); // 파일닫기 46
12-12 문자열단위의파일입출력예 p.621 28 fp = fopen(f_name, "r"); // 주소를저장한파일열기 29 if (fp == NULL) // 파일열기에러처리 30 { printf(" 파일열기에러! \n"); exit(1); } 33 34 printf("\n>> 주소록목록 << \n"); 35 fgets(info, 80, fp); // 파일에서문자열을읽어 info 문자열에저장한다. 36 while (!feof(fp)) // 파일의끝을지나지않았다면반복한다. 37 { 38 printf("%s", info); // 파일에서읽은문자열을모니터에출력한다. 39 fgets(info, 80, fp); // 파일에서문자열을읽어 info 문자열에저장한다. 40 } 41 fclose(fp); // 파일닫기 42 43 return 0; 44 } 47
12.7 이진파일입출력 p.631 텍스트파일 모든데이터가문자열로변환되어기록 예 ) 정수 123456 6개의문자 1, 2, 3, 4, 5, 6 으로변환되어파일에기록 파일에서읽은 6개문자 1, 2, 3, 4, 5, 6 정수 123456로변환됨 이진파일 수치데이터가문자로변환되지않고곧바로수치로저장 정수 123456 정수한개로주기억장치의 4바이트에이진형식으로표현되어저장됨 텍스트파일보다저장공간을적게차지 수치읽을때도한개의수치로바로읽기때문에텍스트파일의수치와문자열간의변환과정이없고, 읽고쓰기가빠름 48
12.7 이진파일입출력 p.631 이진파일은텍스트파일과달리행으로분리되지않으므로행의끝을표시할필요가없으며널문자나개행문자같은글자들도데이터로취급 [ 그림 12-11] (a): 이진파일을 16 진수로출력한화면 (b): 이진파일을메모장에서열었을때의화면 이진파일의데이터읽기과쓰기는 fread 함수와 fwrite 함수사용 49
12.7.1 이진파일에쓰기 : fwrite 함수 p.628 fwrite 함수 블록 ( 연속된데이터집합 ) 단위의파일쓰기 구조체데이터를한번에쓸수있다. fread 함수로이진파일읽기시쓰기를한블록의크기대로읽어야함 형식 FILE *fp = fopen( 파일명, wb ); // w: 쓰기, b: 이진파일 fwrite( 데이터시작주소, 블록크기, 블록개수, 파일포인터명 ); 파일에쓰기 데이터시작주소 부터저장된 블록크기 * 블록개수 바이트를파일에쓴후쓴블록의개수를반환 쓰는데이터의형은달라도되지만이럴경우이진파일에서읽어올때데이터를기록한순서와정확히일치하게읽어야함 50
12-15 구조체멤버를입력받아이진파일로출력하기 p.629 1 #include <stdio.h> // fread, fopen, fclose 함수를위한헤더파일 2 #include <stdlib.h> // exit 함수를위한헤더파일 3 #define SIZE 3 // 정보를입력할사용자수 4 5 struct person // 구조체정의 6 { 7 char name[7], gender[3]; // 이름, 성별 8 int age; // 나이 9 }; 10 typedef struct person PERSN; // 자료형재정의 11 12 int main() 13 { 14 int i; 15 PERSN user; // 사용자정보를저장할구조체변수선언 16 FILE *fp = fopen("user.bin", "wb"); // 쓰기모드로이진파일열기 17 18 if (fp == NULL) // 파일열기에러처리 19 { 20 printf(" 파일열기에러! \n"); exit(1); 21 } 51
12-15 구조체멤버를입력받아이진파일로출력하기 p.629 23 // SIZE 명의사용자정보를키보드에서입력받아이진파일에출력하기 24 printf(">> 사용자정보를입력하세요.(%d 명 )", SIZE); 25 for (i=0; i<size; i++) 26 { 27 printf("\n%d. 이름 : ", i+1); gets(user.name); 28 printf(" 성별 : "); gets(user.gender); 29 printf(" 나이 : "); scanf("%d", &user.age); 31 // user 에저장된사용자정보즉 PERSN 형구조체한개를파일에쓰기 32 fwrite(&user, sizeof(persn), 1, fp); 33 fflush(stdin); // 다음 gets 입력을위해표준입력장치의버퍼비우기 34 } C 프로그램 35 fclose(fp); 36 printf("\n== 파일출력완료 ==\n"); 37 38 return 0; 39 } 블록크기 user 구조체변수 나태희 여 20 fwrite(&user, sizeof(peersn), 1, fp); 나태희 여 20 fp 에연결된파일 52
12.7.2 이진파일읽기 : fread 함수 p.631 fread 함수 이진파일에서데이터블록을읽는함수 형식 FILE *fp = fopen( 파일명, rb ); // r: 읽기, b: 이진파일 fread( 데이터저장주소, 블록크기, 블록개수, 파일포인터명 ); 파일에서읽은블록을저장 파일에서 블록크기 * 블록개수 바이트를읽어서저장주소에저장한후에저장한후읽은블록개수를반환데이터저장주소에해당하는기억장소는 ( 블록크기 * 블록개수 ) 바이트의데이터를저장하기에충분한기억장소여야함 책수정 53
12-16 이진파일의데이터를모니터로출력하기 p.631 [ 프로그램 12-15] 결과인 user.bin 이진파일의내용을모니터로출력하기 1 #include <stdio.h> // fread, fopen, fclose 함수를위한헤더파일 2 #include <stdlib.h> // exit 함수를위한헤더파일 3 4 struct person // 구조체정의 5 { 6 char name[7], gender[3]; // 이름, 성별 7 int age; // 나이 8 }; 9 typedef struct person PERSN; // 자료형재정의 10 11 int main() 12 { 13 PERSN user; // 사용자정보를저장할구조체변수선언 14 FILE *fp; 15 16 fp = fopen("user.bin", "rb"); // 읽기모드로이진파일열기 17 if (fp == NULL) 18 { 19 printf(" 파일열기에러!\n"); exit(1); 20 } 54
12-16 이진파일의데이터를모니터로출력하기 p.631 22 puts("-------------------------------------"); 23 puts(" 이름성별나이 "); 24 puts("-------------------------------------"); 25 26 // 파일에서블록 1 개를제대로읽었다면계속반복하기 27 while (fread(&user, sizeof(persn), 1, fp) == 1) 28 printf(" %-8s %-3s %4d\n", user.name, user.gender, user.age); 29 30 puts("-------------------------------------"); 31 fclose(fp); // 파일닫기 32 33 return 0; 34 } 55
12.8 파일의임의접근 p.633 파일의임의접근 (random access) 순차적접근이아닌파일의임의의위치에서바로읽기 / 쓰기를할수있는접근방식 파일읽기 / 쓰기를시작할위치를가리키는포인터인 파일위치지시자 를조작하는함수가필요 fseek, ftell, rewind 함수를 파일위치지시자 다음에참조 ( 읽기 / 쓰기 ) 할위치를가리키는포인터 키보드의키를누르면글자가나타나는위치를알려주는커서와같은기능 56
12.8 파일의임의접근 p.634 fseek 함수 파일에서다음에읽거나쓸데이터의시작위치를변경 형식 fseek( 파일포인터명, 오프셋, 기준점 ) 파일포인터 에연결된파일의파일위치지시자가 기준점 으로부터 오프셋 만큼떨어진곳을가리키게함 즉, 다음읽기 / 쓰기시작위치를 ( 기준점 + 오프셋 ) 바이트위치로변경기준점 (whence): 오프셋을적용할기준점, 세매크로상수중한개 SEEK_SET: 0 파일시작지점 SEEK_CUR: 1 파일의현재지점 SEEK_END: 2 파일의끝지점 오프셋 (offset): 기준점에서이동할바이트수 기준점이전 음수, 기준점이후 양수 성공하면 0, 실패하면 0이아닌값을반환 57
12.8 파일의임의접근 p.634 예 0 1000 fseek(fp, 100, SEEK_SET) 결과 다음읽기 / 쓰기시작위치 ( 현재 fp 에연결된파일의파일위치지시자가가리키는곳 ) fseek(fp, 200, SEEK_CUR); 결과 fseek(fp, -100, SEEK_END); 결과 rewind( 파일포인터명 ) 파일의다음읽기 / 쓰기위치를파일의시작지점으로이동 fseek(fp, 0, SEEK_SET) 와동일 ftell( 파일포인터변수명 ); 다음읽기 / 쓰기를시작할위치를반환 예 ) rewind(fp); position = ftell(fp); position은 0 58
12.9.1 임의접근을이용한파일정보출력및수정 p.635 문제 [ 프로그램 12-15] 에서만든이진파일의내용을모니터에출력후 사용자로부터수정하고싶은사용자정보를입력받은후 파일의내용을수정하기 이프로그램을다시실행하면파일내용이변경된것을확인가능 59
12.9.1 임의접근을이용한파일정보출력및수정 p.635 분석 파일내용수정시수정할정보가저장된곳으로곧바로이동한후수정 : 임의접근이용 파일에서읽기와수정정보쓰기를해야파일열기모드는 r+b 파일의크기 position 구하기 fseek(fp, 0, SEEK_END); // 파일위치지시자를 ( 파일끝위치 +0) 으로이동 position = ftell(fp); // 파일위치지시자의현위치를 position에저장 파일에저장된사용자정보수 size size = position / sizeof(persn); // 파일에저장된블록의개수 수정정보의위치 사용자에게서정보를수정하고싶은사용자의순번을 no 에입력받는다면 no 번째사용자정보가저장된시작위치는파일시작위치에서 sizeof(persn) * (no-1) 바이트떨어진곳 60
12-17 이진파일에데이터를추가하고모니터로출력하기 p.636 1 #include <stdio.h> // fseek, rewind, ftell 을위한헤더파일 2 #include <stdlib.h> // exit 를위한헤더파일 3 4 typedef struct person // 구조체정의 5 { 6 char name[7]; 7 char gender[3]; 8 int age; 9 } PERSN; // 구조체 struct person 을 PERSN 으로재정의 10 11 int main() 12 { 13 FILE *fp; 14 PERSN user; 15 int size, position, i, no; 16 17 fp = fopen("user.bin", "r+b"); // 읽기 / 쓰기모드로이진파일열기 18 if (fp == NULL) // 파일열기에러처리 19 { 20 printf(" 파일열기에러! \n"); exit(1); 21 } 61
12-17 이진파일에데이터를추가하고모니터로출력하기 p.636 23 // 파일에저장된구조체정보의개수를구하기위해파일위치지시자정보를이용하기 24 fseek(fp, 0, SEEK_END); // ( 파일끝위치 +0) 으로이동하기 25 position = ftell(fp); // 현위치를 position 에저장하기 26 size = position / sizeof(persn); // PERSN 크기의블록개수구하기 27 28 // 파일의내용을읽어서모니터에출력하기 29 puts("------------------------"); 30 puts(" 번호이름성별나이 "); 31 puts("------------------------"); 32 rewind(fp); // 파일의시작위치로이동 33 for (i=0; i<size; i++) 34 { 35 fread(&user, sizeof(persn), 1, fp); 36 printf("%3d %-8s %-3s %4d\n", i+1, user.name, user.gender, user.age); 37 } 38 puts("------------------------"); 62
12-17 이진파일에데이터를추가하고모니터로출력하기 p.636 40 // 정보를수정할번호와수정정보를입력받기 41 printf(" 정보를수정할사용자의번호는? "); scanf("%d", &no); 42 if ((no < 1) (no > size)) // 잘못된입력번호처리 43 { 44 printf(" 번호의범위가잘못되어종료합니다.\n"); exit(1); 45 } 46 printf("\n 이름 : "); scanf("%s", user.name); 47 printf(" 성별 : "); scanf("%s", user.gender); 48 printf(" 나이 : "); scanf("%d", &user.age); 49 50 // 파일위치지시자를 no 번째사용자정보시작위치로이동한후새정보를파일에쓰기 51 fseek(fp, sizeof(persn) * (no-1), SEEK_SET); 52 fwrite(&user, sizeof(persn), 1, fp); 53 54 fclose(fp); 55 printf("\n 파일수정이완료되었습니다. \n"); 56 57 return 0; 58 } 63