쉽게풀어쓴 C 언어 Express 제 16 장파일입출력
이번장에서학습할내용 스트립의개념 표준입출력 파일입출력 입출력관련함수 입출력에관련된개념들과함수들에대하여학습한다.
스트림의개념 스트림 (stream): 입력과출력을바이트 (byte) 들의흐름으로생각하는것
스트림과버퍼 스트림에는기본적으로버퍼가포함되어있다.
표준입출력스트림 기본적인스트림들은프로그래머가생성하지않아도자동으로생성된다. 이름 스트림 연결장치 stdin 표준입력스트림 키보드 stdout 표준출력스트림 모니터의화면 stderr 표준오류스트림 모니터의화면
입출력함수의분류 사용하는스트림에따른분류 표준입출력스트림을사용하여입출력을하는함수 스트림을구체적으로명시해주어야하는입출력함수 스트림형식표준스트림일반스트림설명 getchar() fgetc(file *f,...) 문자입력함수 형식이없는입출력 ( 문자형태 ) putchar() fputc(file *f,...) 문자출력함수 gets() fgets(file *f,...) 문자열입력함수 puts() fputs(file *f,...) 문자열출력함수 형식이있는입출력 ( 정수, 실수,..) printf() fprintf(file *f,...) 형식화된출력함수 scanf() fscanf(file *f,...) 형식화된입력함수
입출력함수의분류 데이터의형식에따른분류 getchar() 나 putchar() 처럼문자형태의데이터를받아들이는입출력 printf() 나 scanf() 처럼구체적인형식을지정할수있는입출력 스트림형식표준스트림일반스트림설명 getchar() fgetc(file *f,...) 문자입력함수 형식이없는입출력 ( 문자형태 ) putchar() fputc(file *f,...) 문자출력함수 gets() fgets(file *f,...) 문자열입력함수 puts() fputs(file *f,...) 문자열출력함수 형식이있는입출력 ( 정수, 실수,..) printf() fprintf(file *f,...) 형식화된출력함수 scanf() fscanf(file *f,...) 형식화된입력함수
스트림과파일 스트림은구체적으로 FILE 구조체를통하여구현 FILE은 stdio.h에정의되어있다.
중간점검 1. C에서의모든입력과출력을 형식으로처리된다. 2. 스트림은모든입력과출력을 들의흐름으로간주한다. 3. 스트림의최대장점은 이다. 4. 입력을위한표준적인스트림은 이고기본적으로 장치와연결된다. 5. 출력을위한표준적인스트림은 이고기본적으로 장치와연결된다.
printf() 를이용한출력 형식제어문자열의구조 출력형식 % [ 플래그 ] [ 필드폭 ] [. 정밀도 ] 형식 출력의정렬과부호출력, 공문자출력, 소수점, 8 진수와 16 진수접두사출력 데이터가출력되는필드의크기 정밀도는소수점이하자릿수의개수가된다.
형식지정자
실수의형식
필드폭과정밀도
필드폭과정밀도
플래그 기호의미기본값 - 출력필드에서출력값을왼쪽정렬한다. 오른쪽정렬된다. + 결과값을출력할때항상 + 와 - 의부호를붙인다. 음수일때만 - 부호를 붙인다. 출력값앞에공백문자대신에 0 으로채운다.- 와 0 0이동시에있으면 0은무시된다. 만약정수출력채우지않는다. 의경우, 정밀도가지정되면역시 0은무시된다 ( 예를들어서 %08.5). blank( ) # 출력값앞에양수나영인경우에는부호대신공백공백을출력하지않는을출력한다. 음수일때는 -가붙여진다.+ 플래그다. 가있으면무시된다. 8진수출력시에는출력값앞에 0을붙이고 16진붙이지않는다. 수출력시에는0x를붙인다.
플래그
중간점검 1. printf() 에서변수나수식의값을출력하는형식을지정하는문자열은 이다. 2. printf() 에서정렬 (alignment) 을구체적으로지시하지않으면기본적으로 정렬된다. 3. 실수를지수표기법으로출력하는데사용되는형식지정자는 이다. 4. 정수를필드폭 6 으로출력하려면 % d 로하여야한다. 5. 실수를필드폭 10 이고소수점이하자리수를 6 자리로출력하려면 % f 로하여야한다. 6. 출력값을왼쪽정렬시키는플래그는 이다. 7. 실수출력의경우, 정밀도를지정하지않았을경우, 소수점이하자리수는기본적으로 개가된다.
scanf() 를이용한입력 문자열형태의입력을사용자가원하는형식으로변환한다.
필드폭지정하여읽기
8 진수, 16 진수입력
문자와문자열입력 분류문자형 형식지정자 %c char 형으로입력받음 %s %[abc] %[^abc] %[0-9] 설명 공백문자가아닌문자부터공백문자가나올때까지를문자열로변환하여입력받음. 대괄호안에있는문자 a,b,c 로만이루어진문자열을읽어들인다. 대괄호안에있는문자 a,b,c 만을제외하고다른문자들로이루어진문자열을읽어들인다. 0 에서 9 까지의범위에있는문자들로이루어진문자열을읽어들인다.
문자와문자열읽기
scanf6.c #include <stdio.h> int main(void) char c; char s[80], t[80]; printf(" 스페이스로분리된문자열을입력하시오 :"); scanf("%s%c%s", s, &c, t); printf(" 입력된첫번째문자열 =%s\n", s); printf(" 입력된문자 =%c\n", c); printf(" 입력된두번째문자열 =%s\n", t); return 0; 스페이스로분리된문자열을입력하시오 :Hello World 입력된첫번째문자열 =Hello 입력된문자 = 입력된두번째문자열 =World
문자집합으로읽기 #include <stdio.h> int main(void) char s[80]; printf(" 문자열을입력하시오 :"); scanf("%[abc]", s); printf(" 입력된문자열 =%s\n", s); return 0; 문자열을입력하시오 :abcdef 입력된문자열 =abc
반환값이용 #include <stdio.h> int main(void) int x, y, z; if (scanf("%d%d%d", &x,&y,&z)== 3) printf(" 정수들의합은 %d\n", x+y+z); else printf(" 입력값이올바르지않습니다.\n"); return 0; 10 20 30 정수들의합은 60 a b c 입력이올바르지않음
scanf() 사용시주의점 입력값을저장할변수의주소를전달 int i; scanf("%d", i); // 오류!! 배열의이름은배열을가리키는포인터 int str[80]; scanf("%s", str); // 올바름 scanf("%s", &str); // 오류!! 충분한공간을확보 int str[80]; scanf("%s", str); // 입력된문자의개수가 79를초과하면치명적인오류발생 scanf() 의형식제어문자열의끝에줄바꿈문자 '\n' 을사용하는것은해당문자가반드시입력되어야한다는의미 scanf("%d\n", &i);// 잘못됨!!
중간점검 1. scanf() 에서 double 값을입력받을때사용하는형식지정자는 이다. 2. 여러개의입력을받는경우, scanf() 는 을이용하여각각의입력을분리한다
파일이필요한이유
파일의개념 C 에서의파일은일련의연속된바이트 모든파일데이터들은결국은바이트로바뀌어서파일에저장 이들바이트들을어떻게해석하느냐는전적으로프로그래머의책임
파일 파일에 4 개의바이트가들어있을때이것을 int 형의정수데이터로도해석할수있고아니면 float 형실수데이터로도해석할수있다 하나의정수? 하나의실수? 4 개의문자? 파일 0x36 0x34 0x31 0x0
텍스트파일 (text file) 텍스트파일은사람이읽을수있는텍스트가들어있는파일 ( 예 ) C 프로그램소스파일이나메모장파일텍스트파일은아스키코드를이용하여저장텍스트파일은연속적인라인들로구성 W O R L D \r \n 윈도우, MS_DOS W O R L D \n C 언어 W O R L D \n 유닉스 W O R L D \r 매킨토시
이진파일 (binary file) 이진파일은사람이읽을수는없으나컴퓨터는읽을수있는파일 이진데이터가직접저장되어있는파일 이진파일은텍스트파일과는달리라인들로분리되지않는다. 모든데이터들은문자열로변환되지않고입출력 이진파일은특정프로그램에의해서만판독이가능 ( 예 ) C 프로그램실행파일, 사운드파일, 이미지파일 #include <stdio.h> #include #include <stdlib.h> <stdio.h> #include <stdlib.h> int main(void) int main(void)... p=(int... *)malloc(100);... p=(int *)malloc(100);... 텍스트파일 : 문자로구성된파일 이진파일 : 데이터로구성된파일
파일처리의개요 파일을다룰때는반드시다음과같은순서를지켜야한다. 파일열기파일읽기와쓰기파일닫기 디스크파일은 FILE 구조체를이용하여접근 FILE 구조체를가리키는포인터를파일포인터 (file pointer)
파일열기 파일에서데이터를읽거나쓸수있도록모든준비를마치는것 FILE *fopen(const char *name, const char *mode) 첫번째매개변수인 name 은파일의이름 두번째매개변수인 mode 는파일을여는모드를의미 FILE *fp; fp = open( test.txt, w );
파일모드 모드 r 읽기모드로파일을연다. w a r+ 설명 쓰기모드로파일을생성한다. 만약파일이존재하지않으면파일이생성된다. 파일이이미존재하면기존의내용이지워진다. 추가모드로파일을연다. 만약똑같은이름의기존의파일이있으면데이터가파일의끝에추가된다. 파일이없으면새로운파일을만든다. 읽기모드로파일을연다. 쓰기모드로전환할수있다. 파일이반드시존재하여야한다. w+ 쓰기모드로파일을생성한다. 읽기모드로전환할수있다. 파일이존재하면기존의데이터가지워진다. a+ 추가모드로파일을연다. 읽기모드로전환할수있다. 데이터를추가하면 EOF 마커를추가된데이터의뒤로이동한다. 파일이없으면새로운파일을만든다. b 이진파일모드로파일을연다.
주의할점 기본적인파일모드에 "t" 나 "b" 를붙일수있다. "a" 나 "a+" 모드는추가모드 (append mode) 라고한다. 추가모드로파일이열리면, 모든쓰기동작은파일의끝에서일어난다. 따라서파일안에있었던기존의데이터는절대지워지지않는다. "r+", "w+", "a+" 파일모드가지정되면읽고쓰기가모두가능하다. 이러한모드를수정모드 (update mode) 라고한다. 읽기모드에서쓰기모드로, 또는쓰기모드에서읽기모드로전환하려면반드시 fflush(), fsetpos(), fseek(), rewind() 중의하나를호출하여야한다.
파일모드 r w a 파일의처음부터읽는다. 파일의처음부터쓴다. 파일의끝에쓴다. 만약파일이존재하면기존파일이없으면생성된다. 의내용이지워진다.
file_open.c #include <stdio.h> int main(void) FILE *fp = NULL; fp = fopen("sample.txt", "w"); if( fp == NULL ) printf(" 파일열기실패 \n"); else printf(" 파일열기성공 \n"); fclose(fp); return 0; 파일열기성공
파일닫기와삭제 파일을닫는함수 int fclose( FILE *stream ); 파일을삭제하는함수 int remove(const char *path) #include <stdio.h> int main( void ) if( remove( "sample.txt" ) == -1 ) printf( "sample.txt 를삭제할수없습니다.\n" ); else printf( "sample.txt 를삭제하였습니다.\n" ); return 0;
중간점검 1. 파일은일련의연속된 라고생각할수있다. 2. 파일에는사람이읽을수있는텍스트가들어있는 파일과사람은읽을수없으나컴퓨터는읽을수있는 파일이있다. 3. 파일을여는라이브러리함수는 이다. 4. fopen() 은 을가리키는포인터를반환한다.
파일입출력함수 파일입출력라이브러리함수 종류설명입력함수출력함수 문자단위문자단위로입출력 int fgetc(file *fp) int fputc(int c, FILE *fp) 문자열단위 문자열단위로입출력 char *fgets(file *fp) int fputs(const char *s, FILE *fp) 서식화된입출력 형식지정입출력 int fscanf(file *fp,...) int fprintf(file *fp,...) 이진데이터이진데이터입출력 fread() fwrite() 크게나누면텍스트입출력함수와이진데이터입출력으로나눌수있습니다.
문자단위입출력 문자입출력함수 int fgetc( FILE *fp ); 파일포인터 int fputc( int c, FILE *fp ); 문자열입출력함수 F I L E char *fgets( char *s, int n, FILE *fp ); 문자열의크기 int fputs( char *s, FILE *fp ); FILE INPUT
문자단위입출력 #include <stdio.h> int main(void) FILE *fp = NULL; fp = fopen("sample.txt", "w"); if( fp == NULL ) printf(" 파일열기실패 \n"); else printf(" 파일열기성공 \n"); fputc('a', fp); fputc('b', fp); fputc('c', fp); fclose(fp); return 0; 파일열기성공 sample.txt abc
문자단위입출력 #include <stdio.h> int main(void) FILE *fp = NULL; int c; fp = fopen("sample.txt", "r"); if( fp == NULL ) printf(" 파일열기실패 \n"); else printf(" 파일열기성공 \n"); while((c = fgetc(fp))!= EOF ) putchar(c); fclose(fp); return 0; 파일열기성공 abc sample.txt abc
문자열단위입출력 #include <stdio.h> #include <stdlib.h> int main(void) FILE *fp1, *fp2; char file1[100], file2[100]; char buffer[100]; printf(" 원본파일이름 : "); scanf("%s", file1); printf(" 복사파일이름 : "); scanf("%s", file2); // 첫번째파일을읽기모드로연다. if( (fp1 = fopen(file1, "r")) == NULL ) fprintf(stderr," 원본파일 %s을열수없습니다.\n", file1); exit(1);
문자열단위입출력 // 두번째파일을쓰기모드로연다. if( (fp2 = fopen(file2, "w")) == NULL ) fprintf(stderr," 복사파일 %s 을열수없습니다.\n", file2); exit(1); // 첫번째파일을두번째파일로복사한다. while( fgets(buffer, 100, fp1)!= NULL ) fputs(buffer, fp2); fclose(fp1); fclose(fp2); return 0; 원본파일이름 : a.txt 복사파일이름 : b.txt
예제 #include <stdio.h> #include <string.h> int main(void) FILE *fp; char fname[128]; char buffer[256]; char word[256]; int line_num = 0; printf(" 입력파일이름을입력하시오 : "); scanf("%s", fname); proverb.txt printf(" 탐색할단어를입력하시오 : "); scanf("%s", word); A chain is only as strong as its weakest link A change is as good as a rest A fool and his money are soon parted A friend in need is a friend indeed A good beginning makes a good ending A little knowledge is a dangerous thing
예제 // 파일을읽기모드로연다. if( (fp = fopen(fname, "r")) == NULL ) fprintf(stderr," 파일 %s 을열수없습니다.\n", fname); exit(1); while( fgets(buffer, 256, fp) ) line_num++; if( strstr(buffer, word) ) printf("%s: %d 단어 %s 이발견되었습니다.\n", fname, line_num, word ); fclose(fp); return 0; 입력파일이름을입력하시오 : proverb.txt 탐색할단어를입력하시오 :house proverb.txt: 7 단어 house 이발견되었습니다. proverb.txt: 8 단어 house 이발견되었습니다.
형식화된출력 int fprintf( FILE *fp, const char *format,...); int i = 23; float f = 1.2345; FILE *fp; fp = fopen("sample.txt", "w"); if( fp!= NULL ) fprintf(fp, "%10d %16.3f", i, f); fclose(fp); %d 와같은특정한형식을지정하여파일에출력할수있습니다.
형식화된입력 int fscanf( FILE *fp, const char *format,...); 1. int i; 2. float f; 3. FILE *fp; 4. 5. fp = fopen("sample.txt", "r"); 6. 7. if( fp!= NULL ) 8. fscanf(fp, "%d %f", &i, &f); 9. printf( %d %f, i, f); 10. 11. fclose(fp): 100 12.345 %d 와같은특정한형식을지정하여파일에입력할수있습니다.
예제 int main(void) FILE *fp; char fname[100]; int number, count = 0; char name[20]; float score, total = 0.0; printf(" 성적파일이름을입력하시오 : "); scanf("%s", fname); // 성적파일을쓰기모드로연다. if( (fp = fopen(fname, "w")) == NULL ) fprintf(stderr," 성적파일 %s 을열수없습니다.\n", fname); exit(1);
예제 // 사용자로부터학번, 이름, 성적을입력받아서파일에저장한다. while( 1 ) printf(" 학번, 이름, 성적을입력하시요 : ( 음수이면종료 )"); scanf("%d", &number); if( number < 0 ) break scanf("%s %f", name, &score); fprintf(fp, "%d %s %f\n", number, name, score); fclose(fp); // 성적파일을읽기모드로연다. if( (fp = fopen(fname, "r")) == NULL ) fprintf(stderr," 성적파일 %s 을열수없습니다.\n", fname); exit(1);
예제 // 파일에서성적을읽어서평균을구한다. while(!feof( fp ) ) fscanf(fp, "%d %s %f", &number, name, &score); total += score; count++; printf(" 평균 = %f\n", total/count); fclose(fp); return 0; 성적파일이름을입력하시오 : score.txt 학번, 이름, 성적을입력하시요 :( 음수이면종료 ) 1 KIM 90.2 학번, 이름, 성적을입력하시요 :( 음수이면종료 ) 2 PARK 30.5 학번, 이름, 성적을입력하시요 :( 음수이면종료 ) 3 MIN 56.8 학번, 이름, 성적을입력하시요 :( 음수이면종료 )-1 평균 = 58.575001
중간점검 1. fgetc() 의반환형은 형이다. 2. 파일에서하나의라인을읽어서반환하는함수는 이다. 3. 텍스트파일에실수나정수를문자열로변경하여저장할때사용하는함수는 이다. 4. 텍스트파일에서실수나정수를읽는함수는 이다.
이진파일쓰기와읽기 텍스트파일과이진파일의차이점 텍스트파일 : 모든데이터가아스키코드로변환되어서저장됨 이진파일 : 컴퓨터에서데이터를표현하는방식그대로저장 텍스트파일 1 2 3 4 5 6 00110001 00110010 00110011 00110100 00110101 00110110 정수 123456 이진파일 00000000 00000001 11100010 01000000
이진파일의생성 파일모드 rb" wb" ab" rb+" "wb+" 읽기모드 + 이진파일모드쓰기모드 + 이진파일모드추가모드 + 이진파일모드읽고쓰기모드 + 이진파일모드쓰고읽기모드 + 이진파일모드 설명 int main(void) FILE *fp = NULL; fp = fopen("binary.txt", "rb"); if( fp == NULL ) printf(" 이진파일열기에실패하였습니다.\n"); else printf(" 이진파일열기에성공하였습니다.\n"); if( fp!= NULL ) fclose(fp);
이진파일쓰기 size_t fwrite( void *buffer, size_t size, size_t count, FILE *fp);
이진파일쓰기 #include <stdio.h> int main(void) int buffer[] = 10, 20, 30, 40, 50 ; FILE *fp = NULL; size_t i, size, count; buffer fp = fopen("binary.bin", "wb"); if( fp == NULL ) fprintf(stderr, "binary.txt 파일을열수없습니다."); exit(1); 항목 size count size = sizeof(buffer[0]); count = sizeof(buffer) / sizeof(buffer[0]); i = fwrite(&buffer, size, count, fp); return 0;
이진파일읽기 size_t fread( void *buffer, size_t size, size_t count, FILE *fp ); #include <stdio.h> #define SIZE 1000 count int main(void) float buffer[size]; FILE *fp = NULL; size_t size; fp = fopen("binary.txt", "rb"); if( fp == NULL ) fprintf(stderr, "binary.txt 파일을열수없습니다."); exit(1); size = fread( &buffer, sizeof(float), SIZE, fp); if( size!= SIZE ) fprintf(stderr, " 읽기동작중오류가발생했습니다.\n"); fclose(fp); return 0; buffer 항목 size
버퍼링 fopen() 을사용하여파일을열면, 버퍼가자동으로만들어진다. 버퍼는파일로부터읽고쓰는데이터의임시저장장소로이용되는메모리의블록 디스크드라이브는블록단위장치이기때문에블록단위로입출력을해야만가장효율적으로동작 1024바이트의블록이일반적 파일과연결된버퍼는파일과물리적인디스크사이의인터페이스로사용 디스크 버퍼 파일
버퍼링 fflush(fp); 버퍼의내용이디스크파일에써진다. setbuf(fp, NULL); setbuf() 는스트림의버퍼를직접지정하는함수로서만약버퍼자리에 NULL을써주면버퍼를제거하겠다는것을의미한다.
예제 #define SIZE 3 struct student int number; char name[20]; double gpa; ; // 이름 // 학번 // 평점 int main(void) struct student table[size] = 1, "Kim", 3.99, 2, "Min", 2.68, 3, "Lee", 4.01 ; struct student s; FILE *fp = NULL; int i; // 이진파일을쓰기모드로연다. if( (fp = fopen("student.dat", "wb")) == NULL ) fprintf(stderr," 출력을위한파일을열수없습니다.\n"); exit(1);
예제 // 배열을파일에저장한다. fwrite(table, sizeof(struct student), SIZE, fp); fclose(fp); // 이진파일을읽기모드로연다. if( (fp = fopen("student.dat", "rb")) == NULL ) fprintf(stderr," 입력을위한파일을열수없습니다.\n"); exit(1); for(i = 0;i < SIZE; i++) fread(&s, sizeof(struct student), 1, fp); printf(" 학번 = %d, 이름 = %s, 평점 = %f\n", s.number, s.name, s.gpa); fclose(fp); return 0; 학번 =1, 이름 =Kim, 평점 = 3.990000 학번 =2, 이름 =Min, 평점 = 2.680000 학번 =3, 이름 = Lee, 평점 = 4.010000
예제 #include <stdio.h> #include <stdlib.h> int main(void) FILE *fp1, *fp2; char file1[100], file2[100]; char buffer[1024]; int count; printf(" 첫번째파일이름 : "); scanf("%s", file1); printf(" 두번째파일이름 : "); scanf("%s", file2); // 첫번째파일을쓰기모드로연다. if( (fp1 = fopen(file1, "rb")) == NULL ) fprintf(stderr," 입력을위한파일을열수없습니다.\n"); exit(1);
예제 // 두번째파일을추가모드로연다. if( (fp2 = fopen(file2, "ab")) == NULL ) fprintf(stderr," 추가를위한파일을열수없습니다.\n"); exit(1); // 첫번째파일을두번째파일끝에추가한다. while((count = fread(buffer, sizeof(char), 1024, fp1)) > 0) fwrite(buffer, sizeof(char), count, fp2); fclose(fp1); fclose(fp2); return 0; 첫번째파일이름 : a.dat 두번째파일이름 : b.dat
예제 다음과같이이진파일의내용을 16 진수로표시하는프로그램을작성하여보자. 흔히이런형식의화면은디버거에서볼수있다. 00000000: 3C 68 74 6D 6C 3E 0D 0A 3C 62 6F 64 79 3E 0D 0A <html>..<body>.. 00000010: 3C 70 72 65 3E 0D 0A 3C 68 31 3E 42 75 69 6C 64 <pre>..<h1>build 00000020: 20 4C 6F 67 3C 2F 68 31 3E 0D 0A 3C 68 33 3E 0D Log</h1>..<h3>. 00000030: 0A 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D.---------------
예제 #include <stdio.h> #include <ctype.h> #include <stdlib.h> int main(void) FILE *fp; char fname[100]; unsigned char buffer[16]; int address = 0; int i, bytes; printf(" 원본파일이름 : "); scanf("%s", fname); if( (fp = fopen(fname, "rb")) == NULL ) fprintf(stderr," 원본파일 %s을열수없습니다.\n", fname); exit(1);
예제 while(1) fclose(fp); return 0; bytes = fread(buffer, 1, 16, fp); if( bytes <= 0 ) break; printf("%08x: ", address); for(i = 0; i < bytes; i++) printf("%02x ", buffer[i]); for(i = 0; i < bytes; i++) if( isprint(buffer[i]) ) putchar(buffer[i]); else putchar('.'); address += bytes; putchar('\n');
임의접근파일 순차접근 (sequential access) 방법 : 데이터를파일의처음부터순차적으로읽거나기록하는방법 임의접근 (random access) 방법 : 파일의어느위치에서든지읽기와쓰기가가능한방법 순차접근파일 임의접근파일
임의접근파일의원리 파일위치표시자 : 읽기와쓰기동작이현재어떤위치에서이루어지는지를나타낸다. 파일위치표시자 강제적으로파일위치표시자를이동시키면임의접근이가능
임의접근관련함수 int fseek(file *fp, long offset, int origin); 상수 값 설명 SEEK_SET 0 파일의시작 SEEK_CUR 1 현재위치 SEEK_END 2 파일의끝 fseek(fp, 0L, SEEK_SET); // 파일의처음으로이동 fseek(fp, 0L, SEEK_END); // 파일의끝으로이동 fseek(fp, 100L, SEEK_SET); // 파일의처음에서 100바이트이동 fseek(fp, 50L, SEEK_CUR); // 현재위치에서 50바이트이동 fseek(fp, -20L, SEEK_END); // 파일의끝에서 20바이트앞으로이동 fseek(fp, sizeof(struct element), SEEK_SET); // 구조체만큼앞으로이동
임의접근관련함수 void rewind(file *fp); 파일위치표시자를 0 으로초기화 long ftell(file *fp); 파일위치표시자의현재위치를반환 파일위치표시자를초기화하고현재위치를알아내는함수들입니다.
예제 #include <stdio.h> #include <stdlib.h> #define SIZE 1000 void init_table(int table[], int size); int main(void) int table[size]; int n, data; long pos; FILE *fp = NULL; // 배열을초기화한다. init_table(table, SIZE); // 이진파일을쓰기모드로연다. if( (fp = fopen("sample.dat", "wb")) == NULL ) fprintf(stderr," 출력을위한파일을열수없습니다.\n"); exit(1);
예제 // 배열을이진모드로파일에저장한다. fwrite(table, sizeof(int), SIZE, fp); fclose(fp); // 이진파일을읽기모드로연다. if( (fp = fopen("sample.dat", "rb")) == NULL ) fprintf(stderr," 입력을위한파일을열수없습니다.\n"); exit(1); // 사용자가선택한위치의정수를파일로부터읽는다. while(1) printf(" 파일에서의위치를입력하십시요 (0에서 %d, 종료-1): ", SIZE - 1); scanf("%d", &n); if( n == -1 ) break pos = (long) n * sizeof(int); fseek(fp, pos, SEEK_SET); fread(&data, sizeof(int), 1, fp); printf("%d 위치의값은 %d입니다.\n", n, data); fclose(fp); return 0;
예제 // 배열을인덱스의제곱으로채운다. void init_table(int table[], int size) int i; for(i = 0; i < size; i++) table[i] = i * i; 파일에서의위치를입력하십시요 (0 에서 999, 종료 -1): 3 3 위치의값은 9 입니다. 파일에서의위치를입력하십시요 (0 에서 999, 종료 -1): 9 9 위치의값은 81 입니다. 파일에서의위치를입력하십시요 (0 에서 999, 종료 -1): -1
중간점검 1. 파일의처음부터순차적으로읽거나쓰는방법을 이라고한다. 2. 파일의어느위치에서나읽고쓰기가가능한방법을 이라고한다. 3. 파일에서읽기나쓰기가수행되면파일의현재의위치를표시하는 가갱신된다. 4. 파일의위치표시자를알아내는함수는 이다.
실습 : 주소록만들기 자신과친한사람들의정보를저장하고업데이트할수있는간단한프로그램을작성하여보자. 입력하거나업데이트한데이터는파일로저장된다. 저장된데이터에대하여검색할수있다. 자기에게필요한여러가지사항들을저장할수있도록하자. 즉자신만의간단한데이터베이스시스템을작성하여보자.
실행결과 ===================== 1. 추가 2. 수정 3. 검색 4. 종료 ===================== 메뉴를선택하세요 : 1 이름 : 홍길동주소 : 서울시종로구 1 번지휴대폰 : 010-123-4567 특징 : 싸움을잘함, 변신에능함...
힌트 파일모드를어떻게해야할까? 적합한것은 a+" 모드이다. 주로추가, 탐색할예정 파일에서읽기전에무조건 fseek() 를해주어야한다. 수정할때는차라리새로운파일을생성하여서거기에전체를다시기록하는것이낫다.
예제 #include <stdio.h> #include <string.h> #define SIZE 100 typedef struct person // 연락처를구조체로표현한다. char name[size]; // 이름 char address[size]; // 주소 char mobilephone[size]; // 휴대폰 char desc[size]; // 특징 PERSON; void menu(); PERSON get_record(); void print_record(person data); void add_record(file *fp); void search_record(file *fp); void update_record(file *fp);
int main(void) FILE *fp; int select; 예제 // 이진파일을추가모드로오픈한다. if( (fp = fopen("address.dat", "a+")) == NULL ) fprintf(stderr," 입력을위한파일을열수없습니다 ); exit(1); while(1) menu(); // 메뉴를표시한다 printf(" 정수값을입력하시오 : "); // 사용자로부터정수를받는다 scanf("%d",&select); switch(select) case 1: add_record(fp); break;// 데이터를추가한다 case 2: update_record(fp); break; // 데이터를수정한다 case 3: search_record(fp); break; // 데이터를탐색한다 case 4: return 0; fclose(fp); // 이진파일을닫는다 return 0;
// 사용자로부터데이터를받아서구조체로반환한다예제 PERSON get_record() PERSON data; fflush(stdin); // 표준입력의버퍼를비운다 printf(" 이름 ); gets(data.name); // 이름을입력받는다 printf(" 주소 ); gets(data.address); // 주소를입력받는다 printf(" 휴대폰 ); gets(data.mobilephone); // 휴대폰번호를 입력받는다 printf(" 특징 ); gets(data.desc); // 특징을입력받는다 return data; // 구조체데이터를화면에출력한다. void print_record(person data) printf(" 이름 \n", data.name); printf(" 주소 \n", data.address); printf(" 휴대폰 \n", data.mobilephone); printf(" 특징 \n", data.desc);
// 메뉴를화면에표시하는함수 void menu() 예제 printf("====================\n"); printf(" 1. 추가 \n 2. 수정 \n 3. 검색 \n 4. 종료 \n"); printf("====================\n"); // 데이터를추가한다 void add_record(file *fp) PERSON data; data = get_record(); // 사용자로부터데이터를받아서구조체에저장 fseek(fp, 0, SEEK_END); // 파일의끝으로간다 fwrite(&data, sizeof(data), 1, fp);// 구조체데이터를파일에쓴다
// 데이터를탐색한다 void search_record(file *fp) char name[size]; PERSON data; fseek(fp, 0, SEEK_SET); fflush(stdin); 예제 // 파일의처음으로간다 printf(" 탐색하고자하는사람의이름 "); gets(name); // 이름을입력받는다 while(!feof(fp)) // 파일의끝까지반복한다 fread(&data, sizeof(data), 1, fp); // 현재위치에서데이터를읽는다 if( strcmp(data.name, name) == 0 ) // 이름을비교한다 print_record(data); // 일치하면데이터를화면에출력한다 break; // 데이터를수정한다 void update_record(file *fp) //...
도전문제 search_record() 에서탐색이실패했으면에러메시지를출력하도록코드를추가하여보라. update_record() 함수를구현하여보자. 앞에서언급한대로수정된부분만파일에덮어쓰는것은상당히어렵다. 따라서수정된전체내용을읽어서새로운파일에쓰도록해보자.
Q & A