C Language 파일입출력 Doo-ok Seo clickseo@gmail.com http://
목 차 파일입출력개념 파일입출력함수 기타파일처리함수 2
파일입출력개념 파일입출력개념 파일의기본개념 파일시스템의개요 FILE 구조체 파일테이블 파일열기및닫기 : fopen, fclose 함수 파일입출력함수 기타파일처리함수 3
파일의기본개념 파일입출력개념 하나의단위로취급해야하는데이터들의외부적컬렉션이다. 파일의종류 텍스트파일 모든데이터가그래픽문자로저장 라인단위로구성되어있으며, 각라인은개행문자 ( \n ) 로끝난다. 이진파일 데이터가정수혹은부동소수점숫자와같은컴퓨터내부표현이그대로저장된다. 파일은보조혹은이차저장장치에저장된다. 4
파일입출력개념 (cont d) 파일의기본개념 (cont d) 메모리와파일의관계 파일은디스크에어떤모습으로존재하는가? : 파일쓰기 01000001 0 1 0 0 0 0 0 1 : 메모리 파일도결국은바이트의연속일뿐이다 디스크 5
파일입출력개념 (cont d) 파일의기본개념 (cont d) 텍스트파일의저장 사용자가입력한문자는 ASCII 코드에대응되는이진수로저장된다. 그림에서는편의상 16 진수로표현했을뿐실제로는이진수의나열이다. Hello enter Hello 저장 48 65 6C 6C 6F 0D 0A 1A H e l l o CR LF ^z 메모장 16진수로표현했지만실제로는0과1로표현되는비트의연속이다. 디스크 6
파일입출력개념 (cont d) 파일의기본개념 (cont d) 텍스트모드와이진모드의차이 48 65 6C 6C 6F 0A 텍스트모드로읽은경우 LF 48 65 6C 6C 6F 0D 0A 1A H e l l o CR LF ^z 48 65 6C 6C 6F 0D 0A 1A 이진모드로읽은경우 이진모드로읽으면 CR과 LF, 그리고 Ctrl-z도단순한데이터로취급하여그대로읽혀진다. 디스크 7
파일입출력개념 (cont d) 파일의기본개념 (cont d) 텍스트모드와이진모드의차이 (cont d) MZ@)?>?jr } 4 E O [ e? T'? *.exe 실행파일 AF 41 EA C8 BD 0D 0A 1A 메모장 4bytes 단위로읽어서 CPU명령어로이해해야할것을 1byte씩읽어억지로 ASCII코드와맵핑한결과 4 Bytes 실행파일은 CPU가이해할수있는 4bytes 명령어의연속된집합으로이진파일이다. 8
파일입출력개념 (cont d) 파일시스템의개요 파일스트림 디스크에존재하는물리적인파일도하나의스트림으로다룬다. 파일스트림은열고나서작업을수행하고난다음반드시닫아야한다. 고수준파일입출력함수 버퍼형파일입출력함수 : buffered file I/O 데이터를파일에서일정블록단위로한번에읽어메모리상에확보된버퍼영역에위치시키는것 버퍼내부의데이터를다양한방법으로조작하고활용가능 호환성이높은프로그램을훨씬유연하게제작할수있다. 저수준파일입출력함수 비버퍼형파일입출력함수 입출력의요구가있을때마다 bytes 단위로읽기 / 쓰기를행하는것 입출력속도가빠르다. 하드웨어에관한부가적인지식을어느정도요구하고개발이어려운편이다. 9
FILE 구조체 파일입출력개념 (cont d) stdio.h 에정의되어있는 FILE 구조체 typedef struct { int level; /* fill/empty level of buffer */ unsigned flags; /* File status flags */ char fd; /* File descriptor */ unsigned char hold; /* Ungetc char if no buffer */ int bsize; /* Buffer size */ unsigned char *buffer; /* Data transfer buffer */ unsigned char *curp; /* Current active pointer */ unsigned istemp; /* Temporary file indicator */ short token; /* Used for validity checking */ } FILE; /* This is the FILE object */ buffer : 버퍼의메모리주소를가리키는포인터변수 curp : 버퍼내의위치를가리키는포인터변수 10
파일테이블 파일입출력개념 (cont d) 프로그램에서파일을사용하는부분과외부파일사이의연결 파일은표준 FILE 형으로정의 표준입출력헤더파일에정의되어있다 <stdio.h> FILE *filename; 식별자가모두대문자이며, 이는미리정의된형의한가지를나타낸다. 별표 (*) 가형의정의에나타나기때문에이형은주소를나타낸다. 파일테이블은파일이름, 파일버퍼의위치, 파일의현재상태등의정보를가지고있다. 11
사용자파일들 파일입출력개념 (cont d) FILE 형을사용하여필요한임의의외부파일을정의 파일은오직하나의스트림과연결된다. 마찬가지로한스트림도오직하나의외부파일과연결된다. 12
파일열기 : fopen 파일입출력개념 (cont d) 외부파일과프로그램사이에연결을만든다. 파일테이블을생성하여파일처리에필요한정보를저장한다. FILE *fopen(const char *filename, const char *mode); filename : 대상파일의경로를포함한이름 mode : 파일의열기모드 대상파일이없거나오류가발생한다면 NULL 을반환한다. FILE *fptemps; if (( fptemps = fopen( TEMPS.DAT, w )) == NULL) { printf( File Open Error\n ); exit(1); } 13
파일열기 (cont d) 파일입출력개념 (cont d) fopen() 함수의파일열기모드 : 텍스트모드 (text mode) 모드 의미 비고 r w a r+ w+ a+ 읽기전용 (Read Only) 파일이없으면 NULL을반환쓰기전용 (Write Only) 파일이존재하지않으면새파일을생성기존파일이있으면그내용은무시하고처음부터새로쓴다. 추가모드 (Append Only) 파일이존재하지않으면새파일을생성기존파일이있으면기존파일의끝에추가만가능하다. 기존파일에대한읽기와쓰기가모두가능하도록파일개방파일이없으면 NULL을반환무조건새로운파일을생성하여읽기와쓰기가가능하도록파일을연다. 기존파일의끝에서부터읽기와쓰기가가능하도록파일을열고, 파일이없으면새로생성한다. 쓰기불가읽기불가읽기불가읽기 + 쓰기읽기 + 쓰기이전부분은쓰기불가 14
파일열기 (cont d) 파일입출력개념 (cont d) fopen() 함수의파일열기모드 : 이진모드 (binary mode) 모드 rb, wb, ab 의미 이진모드로파일을개방하고텍스트모드에서의 r, w, a 와같은의미 r+b, rb+ w+b, wb+ 이진모드로파일을개방하고텍스트모드에서의 r+, w+, a+ 와동일한의미 a+b, ab+ 15
파일닫기 : fclose 파일입출력개념 (cont d) 파일을더이상사용할필요가없을경우에는파일을닫아서버퍼공간과같은시스템자원을반납하여야한다. int fclose(file *fp); #include <stdio.h> 호출성공 : 0 을반환호출실패 : EOF 를반환 int { main (void) FILE *fp;... fp = fopen( test.txt, w );... } fclose(fp); 16
파일입출력개념 (cont d) 전형적인파일처리작업형태 #include <stdio.h> int main() { FILE *fin, *fout; if (fin = fopen( source.txt, r )) == NULL) {... // 에러처리코드 } if (fout = fopen( copy.txt, w )) == NULL) {... }... // 대상파일에대한읽고쓰는작업을수행 fclose(fin); fclose(fout); } return 0; 17
파일입출력함수 파일입출력개념 파일입출력함수 문자입출력함수 : fgetc, fputc 문자열입출력함수 : fgets, fputs 서식화된파일입출력함수 : fscanf, fprintf 이진파일입출력함수 : fread, fwrite 랜덤액세스함수 : fseek, ftell 기타파일처리함수 18
문자입출력함수 : fgetc 파일입출력함수 파일에서한문자 (1 byte) 씩읽는함수 #include <stdio.h> int fgetc (FILE *fp); 호출성공 : 읽어들인한문자의 byte 를 int 형으로반환호출실패또는파일의끝을만나면 : EOF 를반환 fp : 대상이되는파일포인터 파일포인터 fp 가가리키는대상파일에서한문자를읽어 int 형으로반환한다. 19
파일입출력함수 (cont d) 문자입출력함수 : fputc 파일에한문자 (1byte) 씩쓰는함수 #include <stdio.h> int fputc (int ch, FILE *fp); ch : 파일에기록할문자상수 호출성공 : 기록한문자를 int 형으로반환호출실패 : EOF 를반환 fp : 대상이되는파일포인터 파일포인터 fp 가가리키는대상파일에실인자 ch 로전달된한문자를쓴다. 20
파일입출력함수 (cont d) 문자입출력함수 : fgetc 와 fputc 의동작과정 FILE *fp; int ch; fputc( A, fp); fp = fopen(); A ch ch = fgetc(fp); 65 A 디스크 프로그램 21
파일입출력함수 (cont d) 문자입출력함수 : ungetc 지정된문자를입력스트림에되돌려놓는다 (getc 와반대동작 ). 이스트림을다음에읽으면지금되돌려진문자가반환될것이다. #include <stdio.h> int ungetc (int onechar, FILE *stream); option = getc(stdin); if (isdigit(option)) ungetc(option, stdin); else {... } 22
프로그램예제 : fputc() 함수를사용하여데이터를파일에저장 #include <stdio.h> #include <stdlib.h> 파일입출력함수 (cont d) int main() { char FILE ch; *fpout; // data.txt 파일을쓰기모드로개방 fpout = fopen("data.txt", "w"); if (fp == NULL) { printf("data.txt 파일개방실패!!! \n"); exit(100); } 파일에출력 printf(" 저장할문장입력 ( 종료 : Ctrl + Z)... \n"); while ((ch = getchar())!= EOF) fputc(ch, fpout); fclose(fpout); } return 0; 23
프로그램예제 : fgetc() 함수를사용하여데이터를파일에서읽기 #include <stdio.h> #include <stdlib.h> 파일입출력함수 (cont d) int main() { char FILE ch; *fpin; // data.txt 파일을쓰기모드로개방 fpin = fopen("data.txt", r"); if (fp == NULL) { printf("data.txt 파일개방실패!!! \n"); exit(100); } 파일에서읽기 printf( ### 파일내용 ### \n"); while ((ch = fgetc(fpin))!= EOF) putchar(ch); fclose(fpin); } return 0; 24
파일입출력함수 (cont d) 문자열입출력함수 : fgets() 파일에서문자열단위로입력을수행하는함수 #include <stdio.h> char *fgets (char *str, int n, FILE *fp); 호출성공 : str 의주소를반환호출실패 : NULL 을반환 str : 파일에서읽어들인문자열을저장할공간에대한포인터 n : 읽어들일문자열의최대길이 fp : 대상이되는파일포인터 fp가가리키는파일을대상으로 n 1 개의문자를읽어들여 str이가리키는메모리공간에저장한다. 줄바꿈문자 \n 을만나거나파일의끝에도달하면수행을멈춘다. 25
파일입출력함수 (cont d) 문자열입출력함수 : fputs() 파일에서문자열단위로출력을수행하는함수 #include <stdio.h> char *fputs(char *str, FILE *fp); 호출성공 : 음수가아닌정수를반환호출실패 : EOF 를반환 str : 파일에기록할문자열 fp : 대상이되는파일포인터 str 이가리키는문자열을 fp 가가리키는대상파일에저장한다. 26
파일입출력함수 (cont d) 문자열입출력함수 (cont d) fgets 와 fputs 의기본동작 \n 은그대로읽어들 이고 \0 이자동추가 str H e l l o \n \0 fgets(str, 30, fp); Hello\nWorld!\n H e l l o \n \0 fputs(str, fp); Hello\n str \0 은자동제거된 디스크 후기록된다. 27
파일입출력함수 (cont d) 문자열입출력함수 (cont d) fgets 의동작 데이터파일 H e l l o \n W o r l d \n G o o d J o b \n fp 1 파일포인터의최초위치 fp 2 fp 3 파일포인터의최종위치 fp 4 1 fgets(str1, 10, fp); str1 H e l l o \n 2 fgets(str2, 10, fp); str2 W o r l d \n \0 \0 NULL 문자를자동으로덧붙인다. 3 fgets(str3, 10, fp); str3 G o o d J o b \n \0 4 fgets(str4, 10, fp); str4 입력안됨 (fp 는 EOF 를가리키고있음 ) 28
프로그램예제 : fgets 와 fputs 을이용한타자기프로그램 #include <stdio.h> #include <stdlib.h> 파일입출력함수 (cont d) int main (void) { char str[1024]; FILE *fpout; if (!(fpout = fopen ( data.txt", "w"))) { printf( data.txt 파일개방실패!!! \n"); exit (100); } 파일에출력 while ( fgets (str, sizeof (str), stdin) ) fputs (str, fpout); fclose (fpout); return 0; } 29
파일입출력함수 (cont d) 서식화된파일입출력함수 : fscanf 파일을대상으로서식화된입력기능을지원하는함수 #include <stdio.h> char fscanf(file *fp, char *format, 가변길이인수리스트 ); fp : 대상파일포인터 호출성공 : 정수를반환호출실패 : EOF 를반환 format : 서식문자열 가변길이인수리스트 : 파일로부터읽은자료를보관할변수목록 파일에서읽어들인항목수를정수로반환 30
파일입출력함수 (cont d) 서식화된파일입출력함수 : fprintf 파일을대상으로서식화된출력기능을지원하는함수 #include <stdio.h> char fprintf(file *fp, char *format, 가변길이인수리스트 ); fp : 대상파일포인터 호출성공 : 정수를반환호출실패 : EOF 를반환 format : 서식문자열 가변길이인수리스트 : 파일로저장할내용을담고있는변수목록 파일에기록한바이트수를정수로반환 31
파일입출력함수 (cont d) 서식화된파일입출력함수 (cont d) fscanf 사용예 대쉬 (-) 로구분된데이터를읽어서각부분을 3개의정수변수에저장하는 fscanf 함수를작성하라. 입력은 fpin 으로열린파일에서읽는다. 2009-08-15 fscanf(fpdata, %d-%d-%d, &year, &month, &day); fpin 으로열린파일로부터정수를 3개읽고, 성공적으로읽어서변환된변수의수를 result 라는변수에저장하는 fscanf() 함수를작성하라. 5 10 15 result = fscanf(fpdata, %d %d %d, &i, &j, &k); 32
파일입출력함수 (cont d) 서식화된파일입출력함수 (cont d) fscanf 사용예 (cont d) 한라인에정수가네개있는파일이있을때, 각라인에서첫번째, 두번째, 네번째정수만읽는 fscanf 함수를작성하라. 즉세번째정수는버린다. 5 10 15 1 result = fscanf(fpdata, %d%d%*d%d, &a, &b, &d); 33
프로그램예제 : 텍스트파일에서학생성적을읽어들여출력 #include <stdio.h> #include <stdlib.h> 파일입출력함수 (cont d) int main (void) { char name[10]; int kor, eng, math, tot; double ave; FILE *fpin; 파일내용읽기 if (!(fpin = fopen ("data.txt", "r"))) { printf("data.txt 파일개방실패!!! \n"); exit (100); } while ( fscanf(fpin, "%s %d %d %d", name, &kor, &eng, &math) == 4) { tot = kor + eng + math; ave = tot / 3.0; } printf("%10s %3d %3d %3d %5d %8.2f \n", name, kor, eng, math, tot, ave); fclose (fpin); return 0; } 34
파일입출력함수 (cont d) 이진파일입출력함수 : fread, fwrite 이진모드는입출력작업시데이터변환과정을거치지않는다. fread 함수 이진모드로데이터를읽는함수 size_t fread(void *buffer, size_t size, size_t n, FILE *fp); buffer : 파일로부터읽어들인데이터를기억시킬버퍼를가리키는포인터 size : 한번에읽어들일수있는데이터의바이트수 n : size 만큼읽어들이기위해지정하는반복횟수 fp : 대상이되는파일포인터 읽어들인블록 (size의크기를하나의데이터블록 ) 의개수를반환 반환값 : 0 파일의끝을만나더이상읽어들일자료가없거나오류가발생한경우이다. 35
파일입출력함수 (cont d) 이진파일입출력함수 (cont d) fwrite 함수 이진모드로데이터를쓰는함수 size_t fwrite(void *buffer, size_t size, size_t n, FILE *fp); buffer : 파일에기록하고자하는데이터가들어있는버퍼로의포인터 size : 한번에기록할데이터의바이트수 n : size 만큼쓰기위해지정하는반복횟수 fp : 대상이되는파일포인터 자신이기록한블록 (size 의크기를하나의데이터블록 ) 의개수를반환 반환값이 n 이아니라면기록도중오류가발생한경우 36
프로그램예제 : fread() 와 fwrite() 를이용한블록입출력예제 (1/3) #include <stdio.h> #include <stdlib.h> #include <string.h> #include <conio.h> typedef struct student_score // 블록단위입출력을위한성적데이터 { char no[10]; char name[20]; int kor, eng, math, tot; double avg; } INFO; char *fname = "result.txt"; int main() { int cnt = 0; FILE *fp; INFO temp; 파일입출력함수 (cont d) 37
파일입출력함수 (cont d) 프로그램예제 : fread() 와 fwrite() 를이용한블록입출력예제 (2/3) // 이진모드로파일개방 if ((fp = fopen(fname, "wb") ) == NULL ) { printf("file Open Error!\n"); exit(1); } while (1) { printf("\n %d 번째학생정보입력...\n", ++cnt); printf(" 학번 ( 입력종료 : end) : "); gets(temp.no); if(!strcmp(temp.no, "end")) break; printf(" 이름 : "); gets(temp.name); printf(" 국어 : "); scanf("%d", &temp.kor); printf(" 영어 : "); scanf("%d", &temp.eng); printf(" 수학 : "); scanf("%d%*c", &temp.math); temp.tot = temp.kor + temp.eng + temp.math; temp.avg = temp.tot / 3.0; // 기록할때는구조체크기만큼한꺼번에기록한다. fwrite(&temp, sizeof(info), 1, fp); } fclose(fp); 38
파일입출력함수 (cont d) 프로그램예제 : fread() 와 fwrite() 를이용한블록입출력예제 (3/3) printf("\n> 저장된파일정보출력을원하면아무키나누르시오... "); getch(); // 읽어들일때도이진모드로파일개방 if ((fp = fopen(fname, "rb") ) == NULL) { printf("file Open Error!\n"); exit(1); } printf("\n\n===================================\n"); printf("no. NAME KOR ENG MATH TOT AVG\n"); printf("===================================\n"); while (1) { // 구조체 temp 크기만큼읽어온다. cnt = fread(&temp, sizeof(info), 1, fp); if (cnt == 0 cnt == EOF) break; } printf("%s %s %3d %3d %3d %5d %8.2f\n", temp.no, temp.name, temp.kor, temp.eng, temp.math, temp.tot, temp.avg); fclose(fp); return 0; } 39
파일입출력함수 (cont d) 랜덤액세스함수 : fseek, ftell fseek 함수 파일포인터 fp 를임의의위치로이동하는함수 원하는자료에대한직접접근 (direct access) 이가능 int fseek(file *fp, long offset, int whence); fp : 대상이되는파일포인터 offset : whence 위치부터새로운위치까지상대적으로떨어진거리 ( 바이트단위 ) whence : 파일포인터이동을위한기준점 whence SEEK_SET SEEK_CUR SEEK_END 값 0 1 2 의미파일의시작위치를기준으로파일포인터를이동하겠다는뜻현재의파일포인터위치를기준으로다음위치로이동시키겠다는뜻파일의마지막위치를기준으로파일포인터를이동하겠다는뜻 40
파일입출력함수 (cont d) 랜덤액세스함수 (cont d) fseek 함수동작원리 1) fseek(fp, 30L, SEEK_SET); 30 Bytes 데이터파일 \n G o o d o b \n fp 1 파일의시작점을기준으로 30 bytes 이동 fp 2 EOF 2) fseek(fp, -10L, SEEK_CUR); 20 Bytes 파일포인터의현재위치를기준으로 fp 10 bytes 뒤로이동 2 3) fseek(fp, 20L, SEEK_CUR); 20 Bytes 10 Bytes \n G o o d o b fp 1 20 Bytes d o b \n EOF \n fp 1 현재위치를기준으로 20 bytes 앞으로이동 fp 2 EOF 41
파일입출력함수 (cont d) 랜덤액세스함수 (cont d) fseek 함수동작원리 (cont d) 4) fseek(fp, 0L, SEEK_END); 20 Bytes 20 Bytes d o b 파일의끝에서부터 0byte 만큼이동 ( 무조건끝으로이동효과 ) 물론, fseek(fp, 0L, SEEK_SET) 라면무조건처음으로이동한다. EOF \n fp 2 5) fseek(fp, -30L, SEEK_END); 20 Bytes 10 Bytes 30 Bytes EOF 1: fp 이동전 2: fp 이동후 fp 2 파일의끝을기준으로 30bytes 만큼앞으로이동 fp 1 42
파일입출력함수 (cont d) 랜덤액세스함수 (cont d) ftell 함수 파일포인터의위치를얻어오는함수 첫시작위치부터현재 fp 위치까지의거리를 long 형으로알려준다. 오류가발생하면 -1 을반환 int ftell(file *fp); fp : 대상이되는파일포인터 43
기타파일처리함수 파일입출력개념 파일입출력함수 기타파일처리함수 오류처리관련함수 기타함수 44
기타파일처리함수 오류처리관련함수 : feof() feof 함수 파일의끝에도달했는지여부를알려주는함수 파일의끝을읽으면 0 이아닌수를반환하고, 그렇지않은경우는 0 을반환한다. int feof(file *fp); fp : 대상이되는파일포인터 feof 함수의일반적인사용형식 while (!feof(fp)) // 파일의끝이아니라면 putchar(fgetc(fp)); // 한문자씩읽어서화면에바로출력 45
기타파일처리함수 (cont d) 오류처리관련함수 : ferror() ferror 함수 파일처리도중입출력오류가발생할때오류를알려주는함수 파일포인터 fp 와관련된처리에입출력오류가없으면 0 을반환하고, 그렇지않으면 0 이아닌값을반환하여오류를알린다. 파일처리도중에발생할수있는상태» 읽기오류 (read error)» 쓰기오류 (write error)» 파일끝 (end of file) int ferror(file *fp); fp : 대상이되는파일포인터 46
기타파일처리함수 (cont d) 오류처리관련함수 : clearerr() clearerr 함수 error 상태를 clear 하는함수 FILE 구조체의멤버중 flag의 EOF Indicator 비트를 0으로설정하고, ferror() 가설정해놓은 Error Indicator 비트도 0으로만들어오류상태를되돌려놓는역할을한다. void clearerror(file *fp); fp : 대상이되는파일포인터 47
기타파일처리함수 (cont d) 오류처리관련함수 : perror() perror 함수 입출력오류가발생할경우에오류메시지를콘솔로출력하는함수 파일이없거나이미존재하는경우등다수의상황에따른오류코드를 error.h 에매크로상수로정의해두는데, 오류가발생할경우 errno 에자동으로저장된다. void perror(const char *errmsg); errmsg : 출력하려는오류메시지 #include <errno.h>... fp = fopen( perror.txt, r ); if (!fp) { perror( Unable to open file for reading ); printf( errno = %d\n, errno); } 48
기타파일처리함수 (cont d) 기타함수 : fflush() fflush 함수 대상이되는파일버퍼를비우는함수 int fflush(file *fp); fp : 대상이되는파일포인터 fp 가 stdout 인경우는입출력버퍼를비우고, fp 가디스크파일스트림인경우는파일버퍼를비움으로써버퍼의내용을최종적으로디스크에기록한다. 작업이성공적일때는 0을반환하고, 실패한다면 EOF를반환 만약 fp가 NULL인경우라면모든디스크버퍼를비운다. 49
참고문헌 [1] 김일광저, C 프로그래밍입문, 한빛미디어, pp. 356 423. [2] 윤성우, 열혈강의 C 프로그래밍, 프리렉, pp. 537 568. [3] 김진외 7 인공역, 구조적프로그래밍기법을위한 C, 인터비젼, pp. 358 416, pp.772-832. [4] Brian W. Kernighan, Dennis M. Ritchie, The C Programming Language 2/e, 대영사, 206 229. 50