블럭 데이터의 입출력
직접 파일 입력과 출력 현재 사용 중인 C 프로그램이나 또는 다른 어떤 C 프로그램에서 나중에 사용하기 위한 데이터를 저장할 때에는 직접 파일 입출력을 가장 많이 사용한다. 직접 입출력은 이진 모드의 파일에서만 사용된다. 직접 출력을 수행할 때에는 데이터가 블록 단위로 메모리에서 디스크 파일로 저장된다. 직접 입력의 경우에는 이와 반대로 블록 단위의 데이터를 디스크 파일에서 메모리로 읽어들인다. 예를 들어, 직접 출력 함수를 한 번 호출하여 double형의 배열 전체를 디스크에 저장할 수 있고, 직접 입력 함수를 한 번 호출하여 다시 디스크에서 메모리로 전체 배열을 읽어들일 수 있다. 직접 입출력 함수는 fread()와 fwrite()이다. ■ fwrite() 함수 라이브러리 함수 fwrite()는 메모리의 데이터를 블록 단위로 이진 모드의 파일에 기록한다. STDIO.H에 정의되어 있는 함수의 원형은 다음과 같다. int fwrite(void *buf, int size, int count, FILE *fp); 인수 buf는 파일에 기록할 데이터가 저장되어 있는 메모리 영역에 대한 포인터이다. 포인터의 형은 void이므로 어떤 데이터형에 대한 포인터가 될 수 있다. 인수 size는 개별적인 데이터 항목의 크기를 바이트 단위로 지정하는 것이고, count는 기록할 항목의 수를 지정한다. 예를 들어, 100개의 요소를 가지는 정수형 배열을 저장하기 원한다면 각각의 int형은 2바이트를 차지하므로 size는 2가 될 것이고, 배열은 100개의 요소를 가지므로 count는 100이 될 것이다. size 인수를 계산하기 위해서 sizeof() 연산자를 사용할 수 있다. 인수 fp는 물론 파일을 열 때 fopen()이 돌려주는 FILE형에 대한 포인터이다. gwrite() 함수의 동작이 성공적이면 기록한 항목의 개수를 돌려준다. 만약 함수가 돌려주는 값이 count보다 작다면 어던 에러가 발생했다는 것을 알 수 있다. 에러를 확인하기 위해서는 대개 다음과 같이 fwrite()를 사용한다. if((fwrite(buf, size, count, fp) != count) fprintf(stderr, "Error writing to file."); fwrite()를 사용하는 몇 가지 예를 살펴보자. 하나의 double형 변수 X를 파일에 기록하기 위해서 다음과 같이 한다. fwrite(&x, sizeof(double), 1, fp); 50개의 address형 구조체를 가지는 배열 data[]를 파일에 기록하기 위해서는 두 가지 방법을 사용할 수 있다. fwrite(data, sizeof(address), 50, fp); fwrite(data, sizeof(data), 1, fp); 첫 번째 방법에서는 address형의 크기를 가지는 50개의 요소가 배열 포함되어 있는 것으로 계산하여 배열을 저장한다. 두 번째 방법에서는 배열을 하나의 '요소'로 취급한다. 두 가지 방법의 실행 결과는 동일하다. 다음 단원에서는 fread()를 설명하고 나서 fread()와 fwrite()를 사용하는 프로그램을 분석할 것이다. ■ fread() 함수 fread() 라이브러리 함수는 이진 모드의 파일에서 블록 단위의 데이터를 메모리로 읽어들인 다. STDIO.H에 정의되어 있는 함수의 원형은 다음과 같다. int fread(void *buf, int size, int count, FILE *fp); 인수 buf는 파일에서 읽어들인 데이터를 저장할 메모리 영역에 대한 포인터이다. fwrite()에서와 마찬가지로 포인터형은 void이다. 인수 size는 읽어들일 개별적인 데이터 항목의 크기를 바이트 단위로 지정하는 것이고, count는 읽어들일 항목의 개수를 지정한다. 이런 인수들이 fwrite()에서 사용되는 인수들과 같다는 것에 주목하지 바란다. 여기에서도 size 인수를 계산하기 위해서 sizeof() 연산자를 자주 사용한다. 인수 fp는 항상 그렇듯이 파일을 열 때 fopen()이 돌려주는 FILE형에 대한 포인터이다. fread() 함수는 읽어들인 항목의 개수를 돌려준다. 그러나 파일의 마지막에 도달하거나 또는 에러가 발생한다면 이 값은 count보다 작을 수 있다. <리스트 16.4>에 있는 프로그램은 fwrite()와 fread()의 사용 예를 보여준다. <리스트 16.4> 직접 파일 입출력을 위한 fwrite()와 fread()의 사용 /* fwrite()와 fread()를 사용한 직접 파일 입출력 */ #include <stdlib.h> #include <stdio.h> #define SIZE 20 main(0) { int count, array1[SIZE], array2[SIZE]; FILE *fp; /* array1[] 초기화 */ for(count = 0; count < SIZE; count++) array1[SIZE] = 2 * count; /* 이진 모드 파일 열기 */ if((fp = fopen("direct.txt", "wb")) == NULL) { fprintf(stderr, "Error opening file."); exit(1); } /* array1[]을 파일에 저장 */ if(fwrite(array1, sizeof(int), SIZE, fp) != SIZE) { fprintf(stderr, "Error writing to file."); exit(1); } fclose(fp); /* 같은 파일을 이진 모드 읽기 상태로 연다. */ if((fp = fopen("direct.txt", "rb")) == NULL) { fprintf(stderr, "Error epening file."); exit(1); } /* 데이터를 array2[]로 읽어들인다. */ if(fread(array2, sizeof(int), SIZE, fp) != SIZE) { fprintf(stderr, "Error reading file."); exit(1); } fclose(fp); /* 두 배열이 같다는 것을 보여주기 위해 출력 */ for(count = 0; count < SIZE; count++) printf("%dt%dn", array1[count], array2[count]); return(0); } ----------------------------------------------------------------------- 3> fread(), fwrite() ----------------------------------------------------------------------- 이 함수들은 특정 자료형을 글자 단위로 입출력하지 않고 "덩어리 단위"로 읽고 쓴다. 다음의 예를 보자. main() { FILE *fp; char name[20] = "Lim chungha"; fp = fopen("xxx.xxx","w"); fwrite(name, 20,1,fp); <-- (요기) } (요기)를 말로 하면 "name[] 에 있는 데이타들을 파일 fp에 쓰는 데, 덩어리는 20 바이트가 한묶음이고 그런걸 한 덩어리 쓰라"는 얘기다. 즉, 이 경우에는 한 사람의 이름을 파일에 쓰라는 얘기이다. 여기서 name[]의 크기는 사람 이름을 위한 길이를 임의로 넉넉하게 [20] 바이트로 잡았다. fread() 도 마찬가지다. main() { FILE *fp; char name[20]; fp = fopen("xxx.xxx","r"); fread(name, 20,1,fp); <-- (요기) } fread()를 실행하기 전에 name[20]이라는 배열에는 아무 값도 안들 어가 있다. 그러나 위 fwrite()에서 임 청하의 이름을 xxx.xxx 에 성공적으 로 썼다면 위의 (요기)를 실행하고 나면 name[]에 임청하라는 이름이 들어 가 있을 것이다. 이것도 말로 하면 "파일 fp 에서 읽는데 쓸 곳은 name (즉 name[] 배열의 첫집)이다. 크기는 20 바이트짜리 덩어리 한 묶음이다" 이제 다음의 예제를 보자. 친구의 이름과 전화번호를 입력받아 파일에 저장하고 화면에 보여준다. ------------------------------ #include <stdio.h> main(int argc, char *argv[]) { int c; FILE *fp; struct { char name[20]; char tel_no[20]; } entry; char yn; clrscr(); /*------------< write record to file >--------------*/ if((fp = fopen("friends.tel","w")) == NULL) { printf(" can't open .."); exit(1); } do { printf("n 이름 : "); gets(entry.name); printf(" 전화번호 : "); gets(entry.tel_no); fwrite(&entry, sizeof(entry),1,fp); printf("n 계속할까요 (y/n) ? "); yn = getch(); } while ( yn == 'y' || yn == 'Y'); fclose(fp); /*----------< display records >--------------*/ clrscr(); if((fp = fopen("friends.tel","r")) == NULL) { printf(" Can't open file n"); putch(0x07); exit(1); } while(fread(&entry, sizeof(entry),1,fp) == 1) { printf(" %s %sn", entry.name, entry.tel_no); } fclose(fp); getch(); } ----------------------------------------------------------------------- 4> fclose() fread() 함수 : 블럭 단위로 데이터를 읽어들이는 함수 size_t fread( void *ptr, size_t size, size_t n, FILE *fp ); fwrite() 함수 : 블럭 단위로 데이터를 저장 size_t fwrite( const void *ptr, size_t size, size_t n, FILE *fp ); fread()와 fwrite()의 함수를 사용하는 예 #include <stdio.h> #include <stdlib.h> main( int argc, char *argv[ ]) { int c; char yesno; FILE *fp; struct { char name[20]; char tel_no[20]; } entry; if((fp = fopen("friends.tel","w")) == NULL) { printf("!!! 파일을 열 수 없슴n"); exit(1); } do { printf("n 이름 : "); gets(entry.name); printf(" 전화번호 : "); gets(entry.tel_no); fwrite(&entry, sizeof(entry), 1, fp); printf("n 계속할까요 (y/n) ? "); yesno = getche(); } while ( yesno == 'y' || yesno == 'Y'); fclose(fp); if((fp = fopen("friends.tel","r")) == NULL) { printf(" !!! 파일을 열 수 없슴 n"); exit(1); } while( fread ( &entry, sizeof(entry), 1, fp) == 1 ) { printf(" %s %sn", entry.name, entry.tel_no); } fclose(fp); getche(); }
http://codeoz.tistory.com/35