누구나즐기는 C 언어콘서트 제 12 장표준입출력과파일입출력
이번장에서학습할내용 스트립의개념 표준입출력 파일입출력 입출력관련함수 입출력에관련된개념들과함수들에대하여학습한다.
스트림의개념 스트림 (stream): 입력과출력을바이트 (byte) 들의흐름으로생각하는것
스트림과파일 스트림은구체적으로 FILE 구조체를통하여구현 FILE 은 stdio.h 에정의되어있다.
FILE 구조체 struct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; }; typedef struct _iobuf FILE;
표준입출력스트림 표준입출력스트림 (standard input/output stream): 필수적인몇개의스트림 프로그램실행시에자동으로만들어지고프로그램종료시에자동으로없어진다. 이름 스트림 연결장치 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,...) 형식화된입력함수
중간점검 1. C 에서의모든입력과출력을 형식으로처리된다. 2. 스트림은모든입력과출력을 들의흐름으로간주한다. 3. 스트림의최대장점은 이다. 4. 입력을위한표준적인스트림은 이고기본적으로 장치와연결된다. 5. 출력을위한표준적인스트림은 이고기본적으로 장치와연결된다.
printf() 를이용한출력 int printf(char *format,...); 형식제어문자열의구조 %[ 플래그 ] [ 필드폭 ] [. 정밀도 ] [{h l L}] 형식 % 기호 형식제어문자열의시작 플래그 (flag) 출력의정렬과부호출력, 공백문자출력, 소수점, 8 진수와 16 진수접두사출력 필드폭 (width) 과정밀도 (precision) 데이터가출력되는필드의크기 정밀도는소수점이하자릿수의개수가된다.
플래그
필드폭과정밀도
형식
필드폭
정밀도
과학적표기법출력
중간점검 1. printf() 에서변수나수식의값을출력하는형식을지정하는문자열은 이다. 2. printf() 에서정렬 (alignment) 을구체적으로지시하지않으면기본적으로 정렬된다. 3. 실수를지수표기법으로출력하는데사용되는형식지정자는 이다. 4. 정수를필드폭 6 으로출력하려면 % d 로하여야한다. 5. 실수를필드폭 10 이고소수점이하자리수를 6 자리로출력하려면 % f 로하여야한다. 6. 출력값을왼쪽정렬시키는플래그는 이다. 7. 실수출력의경우, 정밀도를지정하지않았을경우, 소수점이하자리수는기본적으로 개가된다.
scanf() 를이용한입력 문자열형태의입력을사용자가원하는형식으로변환한다.
scanf() 의형식제어문자열 %[*] [ 필드폭 ] [{h l L}] 형식 * 현재입력을무시하라는의미 파일에서하나의특정한열만읽을때유용 필드폭 필드폭만큼의문자를읽어서값으로변환 공백문자로입력값을분리하지않고서도여러개의값들을읽을수있다. 크기지정 h 가정수형인경우, short 형으로변환 h 가 float 형앞에붙으면 double 형으로변환 L 은 long double 형으로변환
필드폭지정하여읽기
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
문자집합으로읽기 (1/2) #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) { char s[80]; 문자집합으로읽기 (2/2) printf(" 문자열을입력하시오 :"); scanf("%[a-z]", s); // 알파벳소문자 (a-z) 로구성된문자열만입력 printf(" 입력된문자열 =%s\n", s); } return 0; 문자열을입력하시오 :abcdefghijklmnopqrstuvwxyz 입력된문자열 =abcdefghijklmn
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 형실수데이터로도해석할수있다.
텍스트파일 (text file) 텍스트파일은사람이읽을수있는텍스트가들어있는파일 ( 예 ) C 프로그램소스파일이나메모장파일 텍스트파일은아스키코드를이용하여저장 텍스트파일은연속적인라인들로구성 W O R L D \r \n 윈도우, MS_DOS W O R L D \n W O R L D \n C 언어 유닉스 W O R L D \r 매킨토시
이진파일 (binary file) 이진파일은사람이읽을수는없으나컴퓨터는읽을수있는파일 이진데이터가직접저장되어있는파일 이진파일은텍스트파일과는달리라인들로분리되지않는다. 모든데이터들은문자열로변환되지않고입출력 이진파일은특정프로그램에의해서만판독이가능 ( 예 ) C 프로그램실행파일, 사운드파일, 이미지파일
파일처리의개요 파일을다룰때는반드시다음과같은순서를지켜야한다. 파일열기파일읽기와쓰기파일닫기 디스크파일은 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+ 읽기와추가모드로파일을연다. 만약똑같은이름의기존의파일이있으면데이터가파일의끝에추가된다. 읽기는어떤위치에서나가능하다. 파일이없으면새로운파일을만든다. b 이진파일모드로파일을연다.
파일모드 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,...); int i; float f; FILE *fp; fp = fopen("sample.txt", "r"); if( fp!= NULL ) fscanf(fp, "%d %f", &i, &f); fclose(fp): %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. 텍스트파일에서실수나정수를읽는함수는 이다.
이진파일쓰기와읽기 텍스트파일과이진파일의차이점 텍스트파일 : 모든데이터가아스키코드로변환되어서저장됨 이진파일 : 컴퓨터에서데이터를표현하는방식그대로저장
이진파일의생성 파일모드 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; fp = fopen("binary.bin", "wb"); if( fp == NULL ) { fprintf(stderr, "binary.txt 파일을열수없습니다."); exit(1); } 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; buffer 항목 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;
버퍼링 fopen() 을사용하여파일을열면, 버퍼가자동으로만들어진다. 버퍼는파일로부터읽고쓰는데이터의임시저장장소로이용되는메모리의블록 디스크드라이브는블록단위장치이기때문에블록단위로입출력을해야만가장효율적으로동작 1024 바이트의블록이일반적 파일과연결된버퍼는파일과물리적인디스크사이의인터페이스로사용 디스크 버퍼 파일
예제 #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
임의접근파일 순차접근 (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. 파일의위치표시자를알아내는함수는 이다.
Q & A