2008 Spring Computer Engineering g Programming g 1 Lesson 13 - 제 16 장파일입출력 Lecturer: JUNBEOM YOO jbyoo@konkuk.ac.kr 본강의자료는생능출판사의 PPT 강의자료 를기반으로제작되었습니다.
이번장에서학습할내용 파일의기초 텍스트파일읽기와쓰기 이진파일읽기와쓰기 임의접근파일 파일을이용하면보다많은데이터를유용하고지속적으로사용및관리할수있습니다. 2
파일의개념 C 에서의파일은일련의연속된바이트 모든파일데이터들은결국은바이트로바뀌어서파일에저장 이들바이트들을어떻게해석하느냐는전적으로프로그래머의책임 파일에 4개의바이트가들어있을때이것을 int형의정수데이터로도해석할수있고아니면 float형실수데이터로도해석할수있다. 파일 파일 하나의정수?, 하나의실수?, 4 개의문자? 바이트0 바이트1 바이트2 바이트3 바이트n... 0x36 0x34 0x31 0x0 파일의시작 현재위치 파일의끝 3
텍스트파일 (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 매킨토시 4
이진파일 (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); }... } 텍스트파일 : 문자로구성된파일 이진파일 : 데이터로구성된파일 5
파일열기 파일을다룰때는반드시다음과같은순서를지켜야한다. 파일열기파일읽기와쓰기파일닫기 디스크파일은 FILE 구조체를이용하여접근 FILE 구조체를가리키는포인터를파일포인터 (file pointer) 6
파일열기 파일에서데이터를읽거나쓸수있도록모든준비를마치는것 FILE *fopen(const char *name, const char *mode) 첫번째매개변수인 name은파일의이름 두번째매개변수인 mode는파일을여는모드를의미 모드 r 읽기모드로파일을연다. w a 설명 쓰기모드로파일을생성한다. 만약파일이존재하지않으면파일이생성된다. 파일이이미존재하면기존의내용이지워진다. 추가모드로파일을연다. 만약똑같은이름의기존의파일이있으면데이터가파일의끝에추가된다. 파일이없으면새로운파일을만든다. r+ 읽기와쓰기모드로파일을연다. 파일이반드시존재하여야한다. w+ a+ 읽기와쓰기모드로파일을생성한다. 만약파일이존재하지않으면파일이생성된다. 파일이존재하면새데이터가기존파일의데이터를덮어쓰게된다. 읽기와추가모드로파일을연다. 만약똑같은이름의기존의파일이있으면데이터가파일의끝에추가된다. 읽기는어떤위치에서나가능하다. 파일이없으면새로운파일을만든다. b 이진파일모드로파일을연다 Konkuk. University 7
파일모드 r w a 파일의처음부터읽는다. 파일의처음부터쓴다. 파일의끝에쓴다. 만약파일이존재하면기존파일이없으면생성된다. 의내용이지워진다. 8
file_open.c 1. // 파일열기 2. #include <stdio.h> 3. 4. int main(void) 5. { 6. FILE *fp = NULL; 7. 8. fp = fopen("sample.txt", "w"); 9. 10. if( fp == NULL ) 11. printf(" 파일열기실패 \n"); 12. else 13. printf(" 파일열기성공 \n"); 14. 15. fclose(fp); 16. 17. return 0; 18. } 파일열기성공 9
파일닫기와삭제 파일을닫는함수 int fclose( FILE *stream ); 파일을삭제하는함수 int remove(const char *path) 1. #include <stdio.h> 2. 3. int main( void ) 4. { 5. if( remove( "sample.txt" ) == -1 ) 6. printf( "sample.txt를삭제할수없습니다.\n" ); 7. else 8. printf( "sample.txt를삭제하였습니다.\n" ); 9. 10. return 0; 11. } 10
파일입출력함수 파일입출력라이브러리함수 종류설명입력함수출력함수 문자단위문자단위로입출력 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() 크게나누면텍스트입출력함수와이진데이터입출력으로나눌수있습니다. 11
문자단위입출력 문자입출력함수 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 12
형식화된출력 int fprintf( FILE *fp, const char *format,...); 1. int i = 23; 2. float f = 1.2345; 3. FILE *fp; 4. 5. fp = fopen("sample.txt", "w"); 6. 7. if( fp!= NULL ) 8. fprintf(fp, "%10d %16.3f", i, f); 9. 10. fclose(fp); %d와같은특정한형식을지정하여파일에출력할수있습니다. 13
형식화된입력 int fscanf( FILE *fp fp, const char *format 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. 10. fclose(fp): %d와같은특정한형식을지정하여파일에입력할수있습니다. 14
fcopy1.cc 1. #include <stdio.h> 2. #include <stdlib.h> 3. 4. int main(void) 5. { 6. FILE *fp1, *fp2; 7. char file1[100], file2[100]; 8. char buffer[100]; 9. 10. printf(" 원본파일이름 : "); 11. scanf("%s", file1); 12. 13. printf(" 복사파일이름 : "); 14. scanf("%s", " file2); 15. 16. // 첫번째파일을읽기모드로연다. 17. if( (fp1 = fopen(file1, "r")) == NULL ) 18. { 19. fprintf(stderr," 원본파일 %s을열수없습니다.\n", file1); 20. exit(1); 21. } 15
파일복사예제 22. // 두번째파일을쓰기모드로연다. 23. if( (fp2 = fopen(file2, "w")) == NULL ) 24. { 25. fprintf(stderr," 복사파일 %s을열수없습니다.\n", file2); 26. exit(1); 27. } 28. 29. // 첫번째파일을두번째파일로복사한다. 30. while( fgets(buffer, 100, fp1)!= NULL ) 31. fputs(buffer, ff fp2); 32. 33. fclose(fp1); 34. fclose(fp2); 35. 36. return 0; 37. } 원본파일이름 : a.txt 복사파일이름 : b.txt 16
search.cc 1. #include <stdio.h> 2. #include <string.h> 3. int main(void) 4. { 5. FILE *fp; 6. char fname[128]; 7. char buffer[256]; 8. char word[256]; 9. int line_num = 0; 10. printf(" 입력파일이름을입력하시오 : "); 11. scanf("%s", fname); 12. printf(" 탐색할단어를입력하시오 : "); 13. scanf("%s", word); proverb.txt A chain is only as strong as its weakest link A change is as good as arest A fool and his money are soon parted A friend in need is a friend indeed A good beginning makes a good ending A good man is hard to find A house divided against itself cannot stand A house is not ahome A journey of a thousand miles begins with a single step A leopard cannot change its spots A little knowledge is a dangerous thing 17
search.cc 1. // 파일을읽기모드로연다. 2. if( (fp = fopen(fname, "r")) == NULL ) 3. { 4. fprintf(stderr," 파일 %s을열수없습니다.\n", fname); 5. exit(1); 6. } 7. while( fgets(buffer, 256, fp) ) 8. { 9. line_num++; 10. if( strstr(buffer, word) ) 11. { 12. printf("%s: %d 단어 %s이발견되었습니다.\n", fname, line_num, wor d ); 13. } 14. } 15. fclose(fp); 16. return 0; 17. } 입력파일이름을입력하시오 : proverb.txt 탐색할단어를입력하시오: house proverb.txt: 7 단어 house이발견되었습니다. proverb.txt: 8 단어 house이발견되었습니다. 18
score3.cc 1. #include <stdio.h> 2. #include <stdlib.h> 3. int main(void) 4. { 5. FILE *fp; 6. char fname[100]; 7. int number, count = 0; 8. char name[20]; 9. float score, total = 0.0; 10. printf(" 성적파일이름을입력하시오 : "); 11. scanf("%s", fname); 12. // 성적파일을쓰기모드로연다. 13. if( (fp = fopen(fname, "w")) == NULL ) 14. { 15. fprintf(stderr," 성적파일 %s을열수없습니다.\n", fname); 16. exit(1); 17. } 성적파일이름을입력하시오 : score.txt 학번, 이름, 성적을입력하시요 :( 음수이면종료 ) 1 KIM 90.2 학번, 이름, 성적을입력하시요 : ( 음수이면종료 ) 2 PARK 30.5 학번, 이름, 성적을입력하시요 :( 음수이면종료 ) 3 MIN 56.8 학번, 이름, 성적을입력하시요 :( 음수이면종료 )-1 평균 = 58.575001 19
score3.cc 1. // 사용자로부터학번, 이름, 성적을입력받아서파일에저장한다. 2. while( 1 ) 3. { 4. printf(" 학번, 이름, 성적을입력하시요 : ( 음수이면종료 )"); 5. scanf("%d", &number); 6. if( number < 0 ) break 7. scanf("%s %f", name, &score); 8. fprintf(fp, "%d %s %f\n", number, name, score); 9. } 10. fclose(fp); 11. // 성적파일을읽기모드로연다. 12. if( (fp = fopen(fname, "r")) == NULL ) 13. { 14. fprintf(stderr," 성적파일 %s을열수없습니다.\n", fname); 15. exit(1); 16. } 17. // 파일에서성적을읽어서평균을구한다. 18. while(!feof( fp ) ) 19. { 20. fscanf(fp, f(f "%d %s %f", &number, name, &score); 21. total += score; 22. count++; 23. } 24. printf(" 평균 = %f\n", total/count); 25. fclose(fp); 26. return 0; 27. } 20
이진파일쓰기와읽기 텍스트파일과이진파일의차이점 텍스트파일 : 모든데이터가아스키코드로변환되어서저장됨 이진파일 : 컴퓨터에서데이터를표현하는방식그대로저장 텍스트파일 1 2 3 4 5 6 00110001 00110010 00110011 00110100 00110101 00110110 정수 123456 이진파일 00000000 00000001 11100010 01000000 21
이진파일의생성 rb" wb" 파일모드 읽기모드 + 이진파일모드 쓰기모드 + 이진파일모드 ab" 추가모드 + 이진파일모드 rb+" "wb+" 읽고쓰기모드 + 이진파일모드 쓰고읽기모드 + 이진파일모드 설명 1. int main(void) 2. { 3. FILE *fp = NULL; 4. 5. fp = fopen("binary.txt", "rb"); 6. 7. if( fp == NULL ) 8. printf(" 이진파일열기에실패하였습니다.\n"); 9. else 10. printf(" 이진파일열기에성공하였습니다.\n"); 11. 12. if( fp!= NULL ) fclose(fp); 13. } 22
이진파일읽기 size_t fread( void *buffer, size_t size, size_t count, FILE *fp ); 1. #include <stdio.h> 2. #define SIZE 1000 count 3. int main(void) 4. { 5. float buffer[size]; 6. FILE *fp = NULL; 7. size_t size; buffer 항목 size 8. fp = fopen("binary.txt", "rb"); 9. if( fp == NULL ) 10. { 11. fprintf(stderr, "binary.txt 파일을열수없습니다."); 12. exit(1); 13. } 14. size = fread( &buffer, sizeof(float), SIZE, fp); 15. if( size!= SIZE ) 16. { 17. fprintf(stderr, " 읽기동작중오류가발생했습니다.\n"); 18. } 19. fclose(fp); 20. return 0; 21. } 23
이진파일쓰기 size_t fwrite( void *buffer buffer, size_t size, size_t count, FILE *fp); 1. #include <stdio.h> 2. int main(void) 3. { 4. int buffer[] = { 10, 20, 30, 40, 50 }; 5. FILE *fp = NULL; 6. size_t i, size, count; buffer 7. fp = fopen("binary.txt", "wb"); 8. if( fp == NULL ) 9. { 10. fprintf(stderr, "binary.txt 파일을열수없습니다."); 11. exit(1); 12. } 항목 size count 13. size = sizeof(buffer[0]); 14. count = sizeof(buffer) / sizeof(buffer[0]); 15. i = fwrite(&buffer, size, count, fp); 16. return 0; 17. } 24
버퍼링 fopen() 을사용하여파일을열면, 버퍼가자동으로만들어진다. 버퍼는파일로부터읽고쓰는데이터의임시저장장소로이용되는메모리의블록 디스크드라이브는블록단위장치이기때문에블록단위로입출력을해야만가장효율적으로동작 1024 바이트의블록이일반적 파일과연결된버퍼는파일과물리적인디스크사이의인터페이스로사용 디스크 버퍼 파일 25
binary_file.c 1. #include <stdio.h> 2. #include <stdlib.h> 3. #define SIZE 3 4. struct student { 5. int number; // 학번 6. char name[20]; // 이름 7. double gpa; // 평점 8. }; 9. int main(void) 10. { 11. struct student table[size] = { 12. { 1, "Kim", 3.99 }, 13. { 2, "Min", 2.68 }, 14. { 3, "Lee", 4.01 } 15. }; 16. struct student s; 17. FILE *fp = NULL; 18. int i; 19. // 이진파일을쓰기모드로연다. 20. if( (fp = fopen("student.dat", "wb")) == NULL ) 21. { 22. fprintf(stderr, " 출력을위한파일을열수없습니다.\n"); 23. exit(1); 24. } 25. 26
binary_file.c 1. // 배열을파일에저장한다. 2. fwrite(table, sizeof(struct student), SIZE, fp); 3. fclose(fp); 4. // 이진파일을읽기모드로연다. 5. if( (fp = fopen("student.dat", "rb")) == NULL ) 6. { 7. fprintf(stderr," 입력을위한파일을열수없습니다.\n"); 8. exit(1); 9. } 10. for(i = 0;i < SIZE; i++) 11. { 12. fread(&s, sizeof(struct student), 1, fp); 13. printf(" 학번 = %d, 이름 = %s, 평점 = %f\n", s.number, s.name, s.gpa); 14. } 15. fclose(fp); 16. return 0; 17. } 학번 = 1, 이름 =Kim, 평점 = 3.990000 학번 =2, 이름 =Min, 평점 = 2.680000 학번 =3, 이름 = Lee, 평점 = 4.010000 27
fappend.c 1. #include <stdio.h> 2. #include <stdlib.h> 3. int main(void) 4. { 5. FILE *fp1, *fp2; 6. char file1[100], file2[100]; 7. char buffer[1024]; 8. int count; 9. printf(" 첫번째파일이름 : "); 10. scanf("%s", file1); 11. printf(" 두번째파일이름 : "); 12. scanf("%s", file2); 13. // 첫번째파일을쓰기모드로연다. 14. if( (fp1 = fopen(file1, "rb")) == NULL ) 15. { 16. fprintf(stderr," 입력을위한파일을열수없습니다.\n"); 17. exit(1); 18. } 28
fappend.c 1. // 두번째파일을추가모드로연다. 2. if( (fp2 = fopen(file2, "ab")) == NULL ) 3. { 4. fprintf(stderr," 추가를위한파일을열수없습니다.\n"); 5. exit(1); 6. } 7. // 첫번째파일을두번째파일끝에추가한다. 8. while((count = fread(buffer, sizeof(char), 1024, fp1)) > 0) 9. { 10. fwrite(buffer, sizeof(char), count, fp2); 11. } 12. fclose(fp1); 13. fclose(fp2); 14. return 0; 15. } 첫번째파일이름 :a.dat 두번째파일이름 : b.dat 29
임의접근파일 순차접근 (sequential access) 방법 : 데이터를파일의처음부터순차적으로읽거나기록하는방법 임의접근 (random access) 방법: 파일의어느위치에서든지읽기와쓰기가가능한방법 순차접근파일 임의접근파일 30
임의접근파일의원리 파일위치표시자 : 읽기와쓰기동작이현재어떤위치에서이루어지는지를나타낸다. 파일위치표시자 강제적으로파일위치표시자를이동시키면임의접근이가능 31
임의접근관련함수 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 20L, SEEK_END); END); // 파일의끝에서 20 바이트앞으로이동 fseek(fp, sizeof(struct element), SEEK_SET); // 구조체만큼앞으로이동 32
임의접근관련함수 void rewind(file *fp); 파일위치표시자를 0 으로초기화 long ftell(file *fp); 파일위치표시자의현재위치를반환 파일위치표시자를초기화하고현재위치를알아내는함수들입니다. 33
fseek.c 1. #include <stdio.h> 2. #include <stdlib.h> 3. #define SIZE 1000 4. void init_table(int table[], int size); 5. int main(void) 6. { 7. int table[size]; 8. int n, data; 9. long pos; 10. FILE *fp = NULL; 11. 12. // 배열을초기화한다. 13. init_table(table, table(table SIZE); 14. // 이진파일을쓰기모드로연다. 15. if( (fp = fopen("sample.dat", "wb")) == NULL ) 16. { 17. fprintf(stderr," 출력을위한파일을열수없습니다.\n"); 18. exit(1); 19. } 20. // 배열을이진모드로파일에저장한다. 21. fwrite(table, sizeof(int), SIZE, fp); 22. fclose(fp); 34
fappend.c 1. // 이진파일을읽기모드로연다. 2. if( (fp = fopen("sample.dat", "rb")) == NULL ) 3. { 4. fprintf(stderr," f( 입력을위한파일을열수없습니다.\n"); 5. exit(1); 6. } 7. // 사용자가선택한위치의정수를파일로부터읽는다. 8. while(1) 9. { 10. printf(" 파일에서의위치를입력하십시요 (0에서 %d, 종료-1): ", SIZE - 1); 11. scanf("%d", &n); 12. if( n == -1 ) break 13. pos = (long) n * sizeof(int); 14. fseek(fp, pos, SEEK_SET); 15. fread(&data, sizeof(int), 1, fp); 16. printf("%d 위치의값은 %d입니다.\n", n, data); 17. } 18. fclose(fp); 19. return 0; 20. } 파일에서의위치를입력하십시요 (0에서 999, 종료 -1): 3 21. // 배열을인덱스의제곱으로채운다. 22. void init_table(int table[], int size) 23. { 24. int i; 3 위치의값은 9입니다. 파일에서의위치를입력하십시요 (0에서 999, 종료 -1): 9 9 위치의값은 81입니다. 파일에서의위치를입력하십시요 (0에서 999, 종료 -1): -1 25. for(i = 0; i < size; i++) 26. table[i] = i * i; 27. } 35
Q&A 36