가장 정확하고 일관되게 수를 저장하는 방법은, 프로그램이 사용하는 비트 패턴과 동일한 비트 패턴을 사용하는 것이다. 그러므로, double형 값은 double 형 크기 하나의 단위로만 저장되어야 한다. 프로그램에서 사용하는 표현과 동일한 표현으로 데이터를 파일에 저장할 때, 우리는 그 데이터가 바이너리 형태(binary form)로 저장된다고 말한다.
fread()와 fwrite()함수가 위와 같은 바이너리 형태의 읽고 쓰는 것을 제공한다.
실제로는, 모든 데이터가 바이너리 형태로 저장된다. 문자들도 그 문자 코드의 바이너리 표현을 사용하여 저장된다. 그러나 파일에 있는 모든 데이터가 문자 코드로 해석된다면, 우리는 그 파일이 텍스트 데이터를 가지고 있다고 말한다. 데이터의 일부 또는 전체가 바이너리 형태의 수치 데이터로 해석된다면, 우리는 그 파일이 바이너리 데이터를 가지고 있다고 말한다.
size_t fwrite()함수
fwrite()함수는 다음과 같은 프로토 타입을 가진다.
size_t fwrite(const void * restrict ptr, size_t size, size_t nmemb, FILE * restrict fp);
fwrite()함수는 바이너리 데이터를 파일에 저장한다. size_t 형은 C의 표준 데이터형을 사용하여 정의된다. 이 데이터형은 sizeof 연산자에 의해 리턴되는데, 일반적으로 unsigned int형이다. 포인터 ptr는 저장할 데이터 덩어리의 주소이다. 또한 size는 저장할 그 데이터 덩어리들의 크기(바이트 단위)를 나타낸다. nmemb는 저장할 데이터 덩어리들의 수를 나타낸다. fp는 그 데이터가 저장될 파일을 나타낸다.
ex)
char buffer[256];
fwrite(buffer,256,1,fp);
위 호출은 크기가 256인 데이터 덩어리 하나를 buffer로 부터 파일에 저장한다.
10개의 double형 값으로 이루어진 배열을 저장하려면, 다음과 같이 할 수 있다.
ex)
double earnings[10];
fwrite(earnings,size of(double), 10, fp);
이 호출은 10개의 데이터 덩어리를 earnings 배열로부터 파일로 저장한다. 이때 각각의 데이터 덩어리는 double형 크기를 가진다.
fwrite()함수는 성공적으로 저장한 항목의 수를 리턴한다. 일반적으로 이 값은 nmemb와 같다.
size_t fread()함수
fread()함수는 다음과 같은 프로토 타입을 가진다.
size_t fread(void * restrict ptr, size_t size, size_t nmemb, FILE * restrict fp);
fread()함수는, fwrite()함수가 사용하는 것과 동일한 집합의 전달인자들을 사용한다. 이번에는 ptr이 파일로 부터 읽은 데이터를 저장할 메모리 공간의 주소다. fp는 데이터를 읽을 파일을 나타낸다. fwrite()를 사용하여 파일에 저장된 데이터를 다시 읽기 위해 이 함수를 사용할 수 있다.
앞의 예에서 저장된 10개의 double 형 값으로 이루어진 배열을 다시 읽으려면 다음과 같이 호출할 수 있다.
double earnings[10];
fread(earnings,sizeof(double),10,FILE * fp);
이 호출은 double형 크기의 10개의 값을 읽어 earnings 배열에 복사한다.
fread() 함수는 성공적으로 읽은 항목의 수를 리턴한다. 일반적으로 이 값은 nmemb와 같다.
int feof(FILE * fp)와 int ferror(FILE * fp)함수
표준 입력 함수들이 EOF를 리턴할 때, 일반적으로 그것은 파일의 끝에 도달했다는 것을 의미한다. 그러나 이것은 읽기 에러가 발생했다는 것을 의미할 수도 있다. feof()와 ferror()함수를 사용하면 이 두가지 가능성을 구별 할 수 있다.
feof()함수는 마지막 입력 호출에서 파일의 끝을 만나면 0이 아닌 값을 리턴한다. 그렇지 않으면 0을 리턴한다.
ferror()함수는 읽기 에러나 쓰기 에러가 발생하면 0이 아닌 값을 리턴한다.
바이너리 모드의 파일 입출력을 해야한다면 fread()와 fwrite()함수를 바이너리 모드로 사용하라.
텍스트 모드의 텍스트 입출력을 해야한다면 getc(), putc(), fscanf(), fprintf()같은 함수들을 텍스트 모드로 사용하라.
어떤 파일에 접근하려면 파일 포인터(FILE *)를 생성하고 이 포인터를 특정 파일 이름과 연결하라. 이후 파일을 다룰 때 파일 이름이 아니라 파일 포인터를 사용하면 된다.
'파일의 끝'에 대한 검사는 읽기 시도 직후에 이루어져야 한다. 이유는 C의 입력 함수들은 파일의 끝을 읽고 나서야 그것이 파일의 끝에 도달했다는 것을 인식하기 때문이다.
ex)
int ch;
FILE * fp;
fp = fopen("abc.txt", "r");
ch = getc(fp);
while(ch != EOF)
{
putchar(ch);
ch = getc(fp);
}
,
int ch;
FILE * fp;
fp = fopen("abc.txt","r");
while((ch = getc(fp)) != EOF)
{
putchar(ch);
}
C프로그램은 입력을 바이트들의 스트림으로 인식한다. 파일, 입력장치, 다른 프로그램의 출력이 스트림의 소스가 될 수 있다.
C프로그램은 출력을 바이트 스트림으로 인식한다. 파일, 비디오, 디스플레이 등이 출력스트림의 타깃이 될 수 있다.
fread()와 fwrite() 함수는 바이너리 모드에서 사용된다. 텍스트 모드에선 getc(), putc(), fprintf(), fscanf(), fgets(), fputs() 등을 사용하라.