Download presentation
Presentation is loading. Please wait.
1
C언어를 이용한 화일처리
2
화일의 개념 C에서의 화일은 일련의 연속된 바이트 모든 화일 데이터들은 결국은 바이트(1문자)로 바뀌어서 화일에 저장
이들 바이트들을 어떻게 해석하느냐는 전적으로 프로그래머의 책임 화일에 4개의 바이트가 들어 있을 때 이것을 int형의 정수 데이터로도 해석할 수 있고 아니면 float형 실수 데이터로도 해석할 수 있다.
3
텍스트 화일(text file) 텍스트 화일은 사람이 읽을 수 있는 텍스트가 들어 있는 화일
(예) C 프로그램 소스 화일이나 메모장 화일 텍스트 화일은 아스키 코드를 이용하여 저장 텍스트 화일은 연속적인 라인들로 구성
4
이진 화일(binary file) 이진 화일은 사람이 읽을 수는 없으나 컴퓨터는 읽을 수 있는 화일
이진 데이터가 직접 저장되어 있는 화일 이진 화일은 텍스트 화일과는 달리 라인들로 분리되지 않는다. 모든 데이터들은 문자열로 변환되지 않고 입출력 이진 화일은 특정 프로그램에 의해서만 판독이 가능 (예) C 프로그램 실행 화일, 사운드 화일, 이미지 화일
5
택스트/이진화일의 차이 텍스트 화일과 이진 화일의 차이점 텍스트 화일: 모든 데이터가 아스키 코드로 변환되어서 저장됨
이진 화일: 컴퓨터에서 데이터를 표현하는 방식 그대로 저장
6
화일저장구조 화일은 디스크에 어떤 모습으로 존재하는가? 디스크 1 화일쓰기 : 01000001 … 메모리
디스크 1 화일쓰기 : … 메모리 화일도 결국은 바이트의 연속일 뿐이다 메모리와 화일의 관계
7
화일저장구조 텍스트 화일과 이진화일 48 디스크 65 6C 6F Hello 저장 …
16진수로 표현했지만 실제로는 0과 1로 표현되는 비트의 연속이다 Hello『enter』 메모장 0D 0A 1A H e l o CR LF ^z 텍스트 화일의 저장
8
화일저장구조 텍스트 화일과 이진화일 48 디스크 65 6C 6F …
이진 모드로 읽으면 CR과 LF, 그리고 Ctrl-z도 단순한 데이터로 취급하여 그대로 읽혀진다. 0D 0A 1A H e l o CR LF ^z 텍스트 모드로 읽은 경우 이진 모드로 읽은 경우 텍스트 모드와 이진모드의 차이 1
9
화일저장구조 텍스트 화일과 이진화일 AF 41 EA C8 BD …
실행화일은 CPU가 이해할 수 있는 4바이트 명령어의 연속된 집합으로 이진화일이다. ?>?jr } 4 E O [ e ? T'? 0D 0A 1A *.exe 실행화일 메모장 4 Bytes 4바이트 단위로 읽어서 CPU명령어로 이해해야 할 것을 1바이트씩 읽어 억지로 ASCII코드와 맵핑 한 결과 텍스트 모드와 이진모드의 차이 2
10
파일 입출력의 개념
11
스트림의 이해 스트림(stream): 입력과 출력을 바이트(byte)들의 흐름으로 생각하는 것
12
스트림과 버퍼 스트림에는 기본적으로 버퍼가 포함되어 있다.
13
표준 입출력 스트림 기본적인 스트림들은 프로그래머가 생성하지 않아도 자동으로 생성된다. 이름 스트림 연결 장치 stdin
표준 입력 스트림 키보드 stdout 표준 출력 스트림 모니터의 화면 stderr 표준 오류 스트림
14
입출력 함수의 분류 사용하는 스트림에 따른 분류 표준 입출력 스트림을 사용하여 입출력을 하는 함수
스트림을 구체적으로 명시해 주어야 하는 입출력 함수 스트림 형식 표준 스트림 일반 스트림 설명 형식이 없는 입출력(문자 형태) getchar() fgetc(FILE *f,...) 문자 입력 함수 putchar() fputc(FILE *f,...) 문자 출력 함수 gets() fgets(FILE *f,...) 문자열 입력 함수 puts() fputs(FILE *f,...) 문자열 출력 함수 형식이 있는 입출력(정수, 실수,..) printf() fprintf(FILE *f,...) 형식화된 출력 함수 scanf() fscanf(FILE *f,...) 형식화된 입력 함수
15
스트림과 파일 스트림은 구체적으로 FILE 구조체를 통하여 구현 FILE은 stdio.h에 정의되어 있다.
16
화일 열기 화일을 다룰 때는 반드시 다음과 같은 순서를 지켜야 한다. 디스크 화일은 FILE 구조체를 이용하여 접근
FILE 구조체를 가리키는 포인터를 화일 포인터(file pointer)
17
화일 열기 화일에서 데이터를 읽거나 쓸 수 있도록 모든 준비를 마치는 것 첫 번째 매개 변수인 name은 화일의 이름
두 번째 매개 변수인 mode는 화일을 여는 모드를 의미 FILE *fopen(const char *name, const char *mode)
18
화일 열기 모드(상세) 모드 의 미 비 고 텍스트모드 r
읽기전용(read only)으로 열고 화일이 존재하지 않으면 NULL을 반환한다. write 불가 w 쓰기전용(write only)으로 열고 화일이 존재하지 않으면 새 화일을 생성하고 기존화일이 존재하면 그 내용은 무시하고 처음부터 새로 쓴다. read 불가 a 추가모드(append only)로 열고 화일이 존재하지 않으면 새 화일을 생성하고 존재하면 기존 화일의 끝에 추가만 가능 r+ 기존 화일에 대한 읽기와 쓰기가 모두 가능하도록 화일을 열고 화일이 존재하지 않으면 NULL을 반환 read + write w+ 무조건 새로운 화일을 생성하여 읽기와 쓰기 모두 가능하도록 화일을 연다. a+ 기존 화일의 끝에서부터 읽기와 쓰기가 가능하도록 화일을 열고 화일이 존재하지 않으면 새로 생성한다. 이전부분은 이진모드 rb, wb, ab 이진 모드(binary mode)로 화일을 개방하고 텍스트 모드에서의 r, w, a와 같은 의미를 가짐 r+b, rb+ 이진 모드로 화일을 개방하고 텍스트 모드에서의 r+, w+, a+와 동일한 의미를 가짐 w+b, wb+ a+b, ab+
19
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; } 화일 열기 성공
20
화일 닫기와 삭제 화일을 닫는 함수 화일을 삭제하는 함수 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; }
21
크게 나누면 텍스트 입출력 함수와 이진 데이터 입출력으로 나눌 수 있습니다.
화일 입출력 함수 화일 입출력 라이브러리 함수 종류 설명 입력 함수 출력 함수 문자 단위 문자 단위로 입출력 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() 크게 나누면 텍스트 입출력 함수와 이진 데이터 입출력으로 나눌 수 있습니다.
22
화일 입출력 함수 (1/15) fgetc() puts() int fgetc(FILE *fp);
문자 입출력 함수 : fgetc() 와 fputc() int fgetc(FILE *fp); int fputc(int ch, FILE *fp); ch : 화일에 기록할 문자 상수 fp : 대상이 되는 화일 포인터 fgetc() fp가 가리키는 대상 화일에서 한 바이트를 읽은 다음 그것을 int형으로 반환 오류나 화일의 끝을 만나면 EOF 반환 puts() fp가 가리키는 대상 화일에 실인자 ch로 전달된 한 문자를 기록 정상적으로 저장되었으면 기록했던 문자를 int형으로 반환 오류가 발생하면 EOF 반환 int ch; fputc(‘H’, fp); /* fp가 가리키는 화일에 한 문자를 기록한다 */ ch = fgetc(fp); /* fp가 가리키는 대상 화일에서 한 문자를 읽어 온다 */
23
화일 입출력 함수 (2/15) fgetc()와 fputc()의 동작과정 48 디스크 fputc(‘H’, fp); … H ch
ch =fgetc(fp); 프로그램 FILE *fp; int ch; fp = fopen(); 참고 fgetc(stdin); /* getchar() 와 동일한 기능을 수행한다 */ fputc(‘H’, stdout); /* putchar()와 동일한 기능을 수행한다 */
24
화일 입출력 함수 (3/15) [예제] fputc()와 fgetc()에 의한 화일쓰기와 읽기 예
01 #include <stdio.h> 02 int main() 03 { 04 char ch, *p; 05 char str[] = "Hello, World!\n"; /* 화일에 기록할 문자열 데이터를 준비하고 */ 06 FILE *fin, *fout; /* 화일 포인터를 선언한 다음 */ 07 fout = fopen("data.txt", "w"); /* 화일을 쓰기전용으로 연다 */ 08 if (!fout) { /* 화일포인터가 NULL이면 */ printf("File Open Error\n"); /* 에러메시지를 출력하고 */ exit(1); /* 시스템을 종료한다. */ 11 } 12 p = str; /* 포인터 변수 p가 대상문자열의 첫 번째 문자를 가리키게 한다. */ 13 while (*p) /* p가 가리키는 대상이 NULL이 아닌 동안은 */ 14 { fputc(*p++, fout); /* p가 가리키는 대상 문자 하나를 화일에 기록한다 */ 16 } 17 fclose(fout); /* 쓰기가 끝나면 버퍼를 비우고 화일 스트림을 닫는다. */ 18 fin = fopen("data.txt", "r"); /* 확인을 위해 생성된 화일을 읽기전용으로 연다 */ 19 if (!fin) 20 { printf("File Open Error\n"); exit(1); 23 } 24 while( (ch=fgetc(fin)) != EOF ) /* fin이 가리키는 대상화일에서 한 바이트씩 */ 25 { /* 읽어 들이면서 화일의 끝이 아닌 동안은 */ putchar(ch); /* 읽은 문자를 화면에 출력해 보인다 */ 27 } 28 fclose(fin); /* 화일 스트림을 닫는다 */ 29 return 0; 30 }
25
화일 입출력 함수 (4/15) fgets() fputs()
char *fgets(char *str, int n, FILE *fp); str : 화일에서 읽어 들인 문자열을 저장할 공간에 대한 포인터 n : 읽어 들일 문자열의 최대 길이 fp : 대상이 되는 화일 포인터 int fputs(char *str, FILE *fp); ch : 화일에 기록할 문자열 fgets() fp가 가리키는 화일을 대상으로 n개의 문자를 str에 읽어들인다. 줄바꿈 문자 ‘\n’을 만나거나 화일의 끝에 도달하면 멈춘다. ‘\n’은 그대로 둔 채 str의 끝에 널문자(‘\0’)를 자동 추가한다. fputs() str이 가리키는 문자열을 fp가 가리키는 대상 화일에 저장 str의 끝에 존재하는 널 문자는 기록되지 않는다. ‘\n’을 변환 없이 그대로 화일에 출력한다.
26
화일 입출력 함수 (5/15) fgets()와 fputs()의 기본적인 동작 Hello\nWorld!\n 디스크 …
\0은 자동 제거된 후 기록된다. H e l o \n Hello\n \0 fgets(str, 30, fp); fputs(str, fp); str \n은 그대로 읽어들이고 \0이 자동 추가된다.
27
화일 입출력 함수 (6/15) fgets()의 동작 H e l o \n W r d G J b 데이터 화일 fp ① \0
str1 W r d G J b 데이터 화일 fp ① str2 str3 ① fgets(str1, 10, fp); ② fgets(str2, 10, fp); ③ fgets(str3, 10, fp); \0 ④ fgets(str4, 10, fp); str4 입력 안됨 (fp는 EOF를 가리키고 있음) 화일포인터의 최초위치 화일포인터의 최종위치 ② ③ ④ NULL문자를 자동으로 덧붙인다
28
fcopy1.c #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); }
29
화일 복사 예제 // 두번째 화일을 쓰기 모드로 연다. 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
30
search.c #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); printf("탐색할 단어를 입력하시오: "); scanf("%s", word); proverb.txt 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 good man is hard to find A house divided against itself cannot stand A house is not a home A journey of a thousand miles begins with a single step A leopard cannot change its spots A little knowledge is a dangerous thing
31
search.c // 화일을 읽기 모드로 연다. 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이 발견되었습니다.
32
화일 입출력 함수 (7/15) [예제] fgets()와 fputs()를 이용한 행 단위 입출력 예
01 #include <stdio.h> 02 int main(int argc, char *argv[]) 03 { 04 char str[80]={0,}; /* 한 줄의 최대 길이를 80바이트로 가정하고 */ 05 FILE *fp; 06 if (argc < 2) { printf("Usage: write <filename>\n"); exit(1); 09 } 10 if ((fp = fopen(argv[1], "w")) == NULL) { /* 저장할 화일을 생성한 다음 */ printf("File Open Error\n"); exit(1); 13 } 14 while (1) 15 { gets(str); /* 행 단위 입력을 받아서 */ if (!strcmp(str,":q")) break; /* ‘:q’ 면 종료하고 */ strcat(str, "\n"); /* 아니면 문자열의 끝에 ‘\n’을 붙여서 */ fputs(str, fp); /* 화일에 행 단위로 기록한다. */ 20 } 21 fclose(fp); /* 기록이 끝나면 버퍼를 비우고 화일 스트림을 안전하게 닫는다. */ 22 if ((fp = fopen(argv[1], "r")) == NULL) { /* 저장된 화일을 다시 열고 */ printf("File Open Error\n"); exit(1); 25 } 26 while(fgets(str, 79, fp) != NULL) /* 행 단위로 읽어서 */ 27 { printf(str); /* 결과를 화면에 보여준다. */ 29 } 30 fclose(fp); 31 return 0; 32 }
33
화일 입출력 함수 (8/15) ■ 실행결과 C:\MYC>write hello.txt /* 저장할 화일명을 옵션으로 주고 실행한다 */ Hello, everyone? /* 행단위로 글을 입력하고 */ What are you do'in you guys? Why do you learning C Programming? :q /* 종료 명령을 입력하면 아래와 같이 화일에 저장된 내용을 보여준다. */ Hello, everyone? C:\MYC>type hello.txt /* 저장된 화일의 내용을 type 명령으로 확인 해보고 */ C:\MYC>dir hello.txt /* dir명령으로 화일의 존재도 살펴보자 */ Volume in drive C has no label. Volume Serial Number is 247A-2489 Directory of C:\MYC :04p HELLO.TXT 1 File(s) bytes 0 Dir(s) 2,736,254,976 bytes free C:\MYC> _
34
화일 입출력 함수 (9/15) int *fscanf(FILE *fp, char *format, 가변길이인수리스트);
서식화된 화일 입출력 함수 : fscanf() 와 fprintf() int *fscanf(FILE *fp, char *format, 가변길이인수리스트); fp : 대상이 되는 화일 포인터 format : 서식 문자열 가변길이인수리스트 : 화일로부터 읽은 자료를 보관할 변수 목록 int fprintf(FILE *fp, char *format, 가변길이인수리스트); 가변길이인수리스트 : 화일로 저장할 내용을 담고 있는 변수 목록 작업 대상이 되는 화일 포인터가 존재한다는 것을 제외하면 기본적인 사용법은 scanf()나 printf() 함수와 동일하다.
35
%d와 같은 특정한 형식을 지정하여 화일에 출력할 수 있습니다.
서식화된 출력 int fprintf( FILE *fp, const char *format, ...); int i = 23; float f = ; FILE *fp; fp = fopen("sample.txt", "w"); if( fp != NULL ) fprintf(fp, "%10d %16.3f", i, f); fclose(fp); %d와 같은 특정한 형식을 지정하여 화일에 출력할 수 있습니다.
36
%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와 같은 특정한 형식을 지정하여 화일에 입력할 수 있습니다.
37
score3.c #include <stdio.h> #include <stdlib.h>
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); } 성적 화일 이름을 입력하시오: score.txt 학번, 이름, 성적을 입력하시요: (음수이면 종료) 1 KIM 90.2 학번, 이름, 성적을 입력하시요: (음수이면 종료) 2 PARK 30.5 학번, 이름, 성적을 입력하시요: (음수이면 종료) 3 MIN 56.8 학번, 이름, 성적을 입력하시요: (음수이면 종료)-1 평균 =
38
score3.c // 사용자로부터 학번, 이름, 성적을 입력받아서 화일에 저장한다. 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); return 0;
39
화일 입출력 함수 (10/15) 텍스트 모드에 비해 속도가 빠르다.
이진 화일 입출력 함수 : fread() 와 fwrite() size_t fread(void *buffer, size_t size, size_t n, FILE *fp); buffer: 화일로부터 읽어 들인 데이터를 기억시킬 버퍼로의 포인터 size : 한번에 읽어 들일 수 있는 데이터의 바이트 수 n : size만큼 n 번 읽어 들이기 위해 지정하는 반복 read 회수 fp : 대상이 되는 화일 포인터 size_t fwrite(const void *buffer, size_t size, size_t n, FILE*fp); buffer : 화일에 기록하고자 하는 데이터가 들어있는 버퍼로의 포인터 size : 한번에 기록할 데이터의 바이트 수 n : size만큼 n 번 쓰기 위해 지정하는 반복 write 회수 텍스트 모드에 비해 속도가 빠르다. 내부적인 숫자 표현이나 제어문자에 대한 변환 과정이 없기 때문 많은 양의 데이터를 한꺼번에 읽거나 쓸 때 우수한 성능을 발휘한다.
40
이진 화일 쓰기와 읽기 텍스트 화일과 이진 화일의 차이점 텍스트 화일: 모든 데이터가 아스키 코드로 변환되어서 저장됨
이진 화일: 컴퓨터에서 데이터를 표현하는 방식 그대로 저장
41
이진 화일의 생성 화일 모드 설명 “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); }
42
이진 화일 읽기 size_t fread( void *buffer, size_t size, size_t count, FILE *fp ); #include <stdio.h> #define SIZE 1000 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;
43
이진 화일 쓰기 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.txt", "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;
44
화일 입출력 함수 (11/15) [예제] fwrite()와 fscanf()를 이용한 블록 입출력 예
01 #include <stdio.h> 02 typedef struct score { /* 블록단위 입출력을 위해 성적 데이터를 하나의 */ 03 int no; /* 구조체로 정의한다. 이 때, typedef문에 의해 */ 04 int kor, eng, math, total; /* 구조체 struct score { … } 전체를 STUDENT_SCORE */ 05 float avg; /* 라는 이름으로 쓸 수 있게끔 했다. */ 06 char name[20]; 07 } STUDENT_SCORE; 08 int main() 09 { 10 FILE *fp; 11 int cnt = 0; 12 char name[20]; 13 STUDENT_SCORE s; /* struct student 타입의 구조체 변수 s를 선언 하고 */ 14 char *fname = "result.dat"; 15 printf("=====================\n"); 16 printf("No.KOR ENG MATH NAME\n"); 17 printf("=====================\n"); 18 if ( (fp=fopen(fname, "wb")) == NULL ) { /* 블록단위 입출력을 위해 이진모드로 */ printf("File Open Error!\n"); /* 화일을 연다. */ exit(1); 21 }
45
화일 입출력 함수 (12/15) 22 while (1) { /* 입력 데이터는 여전히 scanf()로 받아 들이고 */
cnt = scanf("%d %d %d %d %s", &s.no, &s.kor, &s.eng, &s.math, s.name); if (cnt == 0 || cnt == EOF) break; s.total = s.kor + s.eng + s.math; s.avg = s.total / 3; fwrite(&s, sizeof(STUDENT_SCORE), 1, fp); /* 기록할 때는 구조체 크기만큼 */ fflush(stdin); /* 한꺼번에 기록한다 */ 29 } 30 fclose(fp); 31 printf("> Press any key, if you want to see the result file?\n"); 32 getch(); 33 if ( (fp=fopen(fname, "rb")) == NULL ) { /* 읽어 들일 때도 이진모드로 화일을 */ printf("File Open Error!\n"); /* 개방해야 한 다음 */ exit(1); 36 } 37 while (1) { cnt = fread(&s, sizeof(STUDENT_SCORE), 1, fp); /* 구조체 s 크기만큼 한꺼번에 */ if (cnt == 0 || cnt == EOF) break; /* 읽어 온다. */ printf("%3d %3d %3d %3d %3d %3.2f %s\n", s.no, s.kor, s.eng, s.math, s.total, s.avg, s.name); 41 } 42 fclose(fp); 43 return 0; 44 }
46
화일 입출력 함수 (13/15) ■ 실행결과 C:\MYC>fwrite /* 프로그램을 실행하고 */
===================== No.KOR ENG MATH NAME kim /* scanf() 형식에 맞춰 데이터를 입력해 준 다음 */ park lee ^Z /* Ctrl-z 를 눌러 입력을 종료하면 화일에 최종적으로 기록된다 */ > Press any key, if you want to see the result file? /* 메시지를 보고 아무키나 누르면 */ kim /* 화일을 이진 모드로 열고 블록단위로 읽어와 보여 준다. */ park lee C:\MYC>type result.dat /* 화일의 내용을 직접 확인해 보면 이진 화일이라는 사실을 확인할 수 있다. */ ☺ P Z d ♫☺ ┤Bkim0‼÷ ┌♣Q♫☻22‼&¶☻ X _ Y ►☺ ┤Bpark0‼÷ ┌♣Q♫☻22‼&¶♥ K X \ ¬Blee 0‼÷ ┌♣Q♫☻22‼&¶ C:\MYC>_ /* 중간 중간 kim, park, lee와 같은 문자도 확인 할 수 있다(잊지말자, 메모장사건 __+). */
47
임의 접근 화일 순차 접근(sequential access) 방법: 데이터를 화일의 처음부터 순차적으로 읽거나 기록하는 방법
임의 접근(random access) 방법: 화일의 어느 위치에서든지 읽기와 쓰기가 가능한 방법
48
임의 접근 화일의 원리 화일 위치 표시자: 읽기와 쓰기 동작이 현재 어떤 위치에서 이루어지는 지를 나타낸다.
강제적으로 화일 위치 표시자를 이동시키면 임의 접근이 가능 화일 위치 표시자
49
임의 접근 관련 함수 int fseek(FILE *fp, long offset, int origin); 상수 값 설명
SEEK_SET 화일의 시작 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); // 구조체만큼 앞으로 이동
50
화일 위치 표시자를 초기화하고 현재 위치를 알아내는 함수들입니다.
임의 접근 관련 함수 void rewind(FILE *fp); 화일 위치 표시자를 0으로 초기화 long ftell(FILE *fp); 화일 위치 표시자의 현재 위치를 반환 화일 위치 표시자를 초기화하고 현재 위치를 알아내는 함수들입니다.
51
화일 입출력 함수 (14/15) 랜덤 액세스 함수 : fseek(), ftell()
int fseek(FILE *fp, long offset, int whence); fp : 대상이 되는 화일 포인터 offset : whence 위치부터 새로운 위치까지의 상대적으로 떨어진 거리(바이트 수) whence : 화일포인터 이동을 위한 기준점 long ftell(FILE *fp); fseek() 함수의 whence의 의미 whence 값 의미 SEEK_SET 화일의 시작위치를 기준으로 화일포인터를 이동하겠다는 뜻 SEEK_CUR 1 현재의 화일포인터 위치를 기준으로 다음 위치로 이동시키겠다는 뜻 SEEK_END 2 화일의 마지막 위치를 기준으로 화일포인터를 이동하겠다는 뜻 fseek(fp, 30L, SEEK_SET); /* == fseek(fp, 20L, 0); */
52
화일 입출력 함수 (15/15) 30 Bytes \n G o d … b 데이터 화일 fp ①
1) fseek(fp, 30L, SEEK_SET); 화일의 시작점을 기준으로 30 바이트 이동 EOF ② 20 Bytes 10 Bytes 2) fseek(fp, -10L, SEEK_CUR); 화일포인터의 현재 위치를 기준으로 10바이트 뒤로 이동 3) fseek(fp, 20L, SEEK_CUR); 현재 위치를 기준으로 20 바이트 앞으로 이동 4) fseek(fp, 0L, SEEK_END); 화일의 끝에서부터 0바이트 만큼 이동 (무조건 끝으로 이동 효과) 물론, fseek(fp, 0L, SEEK_SET) 라면 무조건 처음으로 이동한다. 5) fseek(fp, -30L, SEEK_END); 화일의 끝을 기준으로 30바이트 만큼 앞으로 이동 ① : fp 이동 전 ② : fp 이동 후
53
fseek.c #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);
54
fappend.c // 이진 화일을 읽기 모드로 연다.
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
55
기타 화일처리 함수 (1/7) feof() int feof(FILE *fp); fp : 대상이 되는 화일 포인터
에러처리 관련 함수 : feof(), ferror(), clearer(), perror() int feof(FILE *fp); fp : 대상이 되는 화일 포인터 ferror(FILE *fp); void clearerr(FILE *fp); void perror(const char *errmsg); errmsg : 출력하고자 하는 에러 메시지 feof() 화일의 끝을 읽게 되면 0아닌 수를 반환 화일의 끝인지 검사 이진 모드로 읽을 때 유용 while (!feof(fp)) /* 화일의 끝이 아니라면 */ putchar(fgetc(fp)); /* 한 문자씩 읽어서 화면에 바로 출력 */
56
기타 화일처리 함수 (2/7) ferror() clearerr()
fp와 관련된 처리에서 입출력 에러가 발생하면 0아닌 값을 반환 while (!feof(fp)) { /* 얘는 화일의 끝만 검사할 뿐이지 오류여부는 검사 안 한다. */ ch = fgetc(fp); if (!ferror(fp)) /* 따라서, ferror()로 입출력 오류 여부를 물어 보고 */ putchar(ch); /* 에러가 없으면 문자를 출력한다. */ else { /* 그렇지 않으면 오류 메시지를 보여주고 */ printf(“OOPs, FILE I/O Error!!\n”); break; /* 처리를 중단한다. */ } clearerr() FILE 구조체의 멤버 중 flag의 EOF Indicator 비트를 0으로 세팅하여 발생한 에러 상황을 클리어한다. ferror()에 의해 설정된 에러 상황을 제거할 때 사용
57
기타 화일처리 함수 (3/7) perror() 입출력 오류가 발생할 경우의 에러 메시지를 콘솔로 출력
#include <errno.h> … fp = fopen("perror.dat", "r"); if (!fp) { perror("Unable to open file for reading"); /* 사용자 정의 문자열 외 시스템에서 정하고 */ printf(“errno = %d\n”, errno); /* 있는 메시지와 에러코드가 함께 출력된다 */ } 화일이 존재하지 않거나 이미 존재하는 경우 등 다수의 상황에 따른 에러 코드가 error.h 에 매크로 상수로 정의되어 있고, 오류 발생 시 errno 에 자동 저장된다.
58
기타 화일처리 함수 (4/7) 화일시스템 관련 함수 : rename(), remove(), tmpfile(), tmpnam()
int rename(const char *oldname, const char *newname); odlname : 원래의 화일 이름 newname : 변경할 화일 이름 int remove(const char *filename); /* UNIX 시스템에서는 unlink() */ filename : 삭제하고자 하는 화일 이름 FILE *tmpfile(void); char *tmpnam(char *sptr); sptr : 생성된 Temporary file name을 저장할 공간으로의 포인터 rename() 디스크 상의 화일 이름을 변경 newname은 현재 디렉토리에 존재하지 않는 화일명이어야 한다. 성공적이면 0을, 그렇지 않으면 0아닌 값을 반환
59
기타 화일처리 함수 (5/7) remove() tmpfile() tmpnam() 디스크 상의 화일을 삭제한다.
성공하면 0을 실패하면 0아닌 값을 반환 if (remove(args[1]) == 0) printf("Removed %s.\n",args[1]); else perror("remove"); tmpfile() 디스크에 새 화일을 “wb+” 모드로 생성 생성된 임시 화일은 프로그램이 종료되면 자동적으로 디스크에서 삭제된다. 임시화일을 생성하지 못하면 NULL을 반환한다. FILE *tfp = tmpfile(); if (!tfp) { perror(“Can’t open temporary file\n”); exit(1); } …tfp 를 이용해 임시 화일에 읽고 쓰기 작업 수행… tmpnam() 새 화일명을 생성하고 sptr이 가리키는 메모리 공간에 넣어준다. 생성된 화일명을 이용해 fopen()으로 새로운 화일을 개방할 수 있다.
60
기타 화일처리 함수 (6/7) int fgetpos(FILE *fp, fpos_t *pos); fp : 대상 화일 포인터
화일포인터 처리 관련 함수 : fgetpos(), fsetpos(), rewind() int fgetpos(FILE *fp, fpos_t *pos); fp : 대상 화일 포인터 pos : 화일 포인터의 현재 위치를 받아올 인자 int fsetpos(FILE *fp, const fpos_t *pos); fp : 대상이 되는 화일 포인터 pos : 이동하고자 하는 화일 포인터의 위치 void rewind(FILE *fp); fgetpos()와 fsetpos() 화일 포인터 위치를 얻거나 새로운 위치로 화일 포인터를 설정 fpos_t는 화일포인터의 위치 값을 long형으로 보관해두기 위한 목적의 변수를 선언할 때 많이 사용 (typedef long fpos_t, in stdio.h) rewind() 화일 포인터를 화일의 처음으로 이동 화일버퍼는 자동으로 비워짐 fseek(fp, 0L, SEEK_SET)과 동일, 주로 텍스트 화일을 다룰 때 사용
61
기타 화일처리 함수 (7/7) fgetpos()와 fsetpos()는 주로 함께 사용 fpos_t pos /* 화일포인터 보관을 위한 변수 선언, long pos; 로 선언한 것과 같다 */ fgetpos(fp, &pos); /* 현재의 화일 포인터 위치를 얻어 온다. pos = ftell(fp) 과 같다 */ … 화일 포인터를 이리 저리 옮겨 다니면서 작업을 수행하다가 … fsetpos(fp, &pos); /* 작업 전의 원래의 위치로 화일포인터를 되돌려 놓는다 */ 기타 함수 : flush() int fflush(FILE *fp); fp : 대상 화일 포인터 flush() 대상이 되는 화일 버퍼를 비운다. fp가 stdout인 경우는 입출력 버퍼를 비우고 fp가 디스크 화일 스트림인 경우는 화일 버퍼를 비움으로써 버퍼의 내용이 최종적으로 디스크에 기록되게 한다. 성공적일 때는 0, 실패한다면 EOF를 반환 fp가 NULL인 경우라면 모든 디스크 버퍼를 비운다.
Similar presentations