[C언어] 7. 파일 입출력
제가 책(윤성우의 열혈 C 프로그래밍)을 보다가 까먹었던 부분만 포스팅 하는 것입니다!
순서가 뒤죽박죽이어도 이해해주세요~~!
파일과 스트림
파일로부터 데이터를 읽어 들이려면(파일에 데이터를 쓰려면)
프로그램과 파일 사이에 스트림이 형성되어야 합니다.
파일은 운영체제에 의해서 그 구조가 결정되고 관리되는 대상이기 때문에,
파일 뿐만 아니라 스트림의 형성도 운영체제의 몫입니다.
스트림을 형성할 때 호출하는 함수는 fopen입니다~
#include <stdio.h>
FILE * fopen(const char *filename,const char * mode);
//성공 시 해당 파일의 FILE 구조체 변수의 주소 값, 실패 시 NULL 포인터 반환
//FILE * 는 파일을 가리키는 포인터라고 생각!
예를 들어 다음과 같이 사용합니다.
#include <stdio.h>
int main(void)
{
FILE *fp=fopen("data.txt","wt"); //텍스트 데이터 출력용 스트림 형성
if(fp==NULL){
printf("파일오픈실패");
return -1;
}
fputc('A',fp); //fp가 지칭하는 data.txt에 문자 A가 저장됩니다.
fclose(fp); //스트림의 종료
return 0;
}
파일로부터 데이터를 읽어드리는 건 다음과 같습니다.
#include <stdio.h>
int main(void)
{
FILE *fp=fopen("data.txt","rt"); //텍스트 데이터 입력용 스트림 형성
if(fp==NULL){
printf("파일오픈실패");
return -1;
}
int ch=fgetc(fp);
//fp가 지칭하는 data.txt에 있는 문자 A를 가져와 ch에 저장합니다.
fclose(fp); //스트림의 종료
return 0;
}
그리고 개방되었던 파일은 fclose 함수로 닫아주어야 합니다~
파일의 개방모드
fopen 함수의 두 번째 인자로 “wt”와 “rt” 를 전달하여 스트림을 형성하였습니다.
형성할 수 있는 스트림의 종류는 훨씬 더 다양합니다.
rt : 텍스트모드 읽기가능
wt : 텍스트모드 쓰기가능
at : 텍스트모드 파일의 끝에 덧붙여 쓰기 가능
rb : 바이너리모드 읽기가능
wb : 바이너리모드 쓰기가능
ab : 바이너리모드 파일의 끝에 덧붙여 쓰기 가능
바이너리 파일은 영상, 음원파일 등 컴퓨터가 인식하는 데이터를 담고 있는 파일이고,
텍스트 파일은 사람이 인식할 수 있는 문자를 담고 있는 파일입니다.
모드를 텍스트, 바이너리로 나누는 이유는 대표적으로 \n 입니다.
개행은 일반적으로 c언어에서만 ‘\n’ 으로 사용합니다.
MS-DOS의 파일 내 개행은 ‘\r\n’ 입니다
그렇기에 파일을 텍스트 모드로 개방하면 자동으로 ‘\r\n’을 ‘\n’으로 바꾸어 줍니다~!
파일 입출력 함수의 기본
개방된 파일(텍스트 파일) 대상으로의 데이터 입력과 출력 함수는 다음과 같습니다.
int fputc(int c, FILE * stream)
int fgetc(FILE * stream)
int fputs(const char* s, FILE * stream)
char * fgets(char* s, int n, FILE * stream)
구체적인 방법은 5.문자와 문자열 관련 함수 를 참고 하시길 바랍니다.
feof 함수 기반의 파일복사 프로그램
파일의 끝을 확인하는 함수는 다음과 같습니다.
#include <stdio.h>
int feof(FILE * stream);
//파일의 끝에 도달한 경우 0이 아닌 값 반환
이를 이용하여 파일 복사 프로그램을 작성해보겠습니다~
#include <stdio.h>
int main(void)
{
FILE * src=fopen("src.txt","rt");
FILE * des=fopen("des,txt","wt");
int ch;
if(src==NULL||des==NULL)
{
printf("파일오픈실패");
return -1;
}
while((ch=fgetc(src))!=EOF)
fputc(ch,des);
if(feof(src)!=0) //파일 src 끝까지 복사됐는지 확인
printf("파일복사 완료!");
else
printf("파일복사 실패!");
fclose(src);
fclose(des);
return 0;
}
바이너리 데이터의 입출력: fread, fwrite
바이너리 데이터의 입력에 사용되는 함수는 다음과 같습니다.
int buf[12];
fread((void*)buf,sizeof(int),12,fp); //fp는 FILE 구조체 포인터
위의 호출문은 다음의 의미로 해석됩니다.
sizeof(int) 크기의 데이터 12개를 fp로부터 읽어 들여서 배열 buf에 저장하라!
그리고 바이너리 데이터의 출력에 사용되는 함수는 다음과 같습니다.
int buf[7]={1,2,3,4,5,6,7};
fwrite((void*)buf,sizeof(int),7,fp);
위의 호출문은 다음의 의미로 해석됩니다.
sizeof(int) 크기의 데이터 7개를 buf로부터 읽어서 fp에 저장하라!
서식에 따른 데이터 입출력: fprintf, fscanf
두 개의 텍스트 데이터와 하나의 바이너리 데이터를 출력해야 하는 상황에서,
제일 먼저 생각할 수 있는 방법은 fscanf 함수와 fprintf 함수의 호출입니다.
fprintf 호출방법은 다음과 같습니다.
char name[10]="꾸리"; //텍스트 데이터
char sex='M'; //텍스트 데이터 남자 M
int age=24; //바이너리 데이터
fprintf(fp, "%s %c %d",name,sex,age); //fp는 FILE 구조체 포인터
//텍스트 데이터와 바이너리 데이터가 하나의 문자열로 묶여져서 파일에 저장됩니다.
fscanf 호출방법은 다음과 같습니다
char name[10];
char sex;
int age;
fscanf(fp, "%s %c %d",name,&sex,&age); //fp는 FILE 구조체 포인터
//단, 데이터 읽는 순서와 데이터의 저장순서가 일치해야 합니다.
그리고 구조체 변수를 파일로부터 입출력 할 때도,
바이너리 입출력 함수 fwrite와 fread를 이용합니다.
파일 위치 지시자
경우에 따라서는 파일의 중간 또는 마지막 부분에
저장된 데이터의 일부를 읽어야하는 경우도 있습니다~
이 때는 ‘파일 위치 지시자’라는 것을 파일의 중간 또는 마지막 부분에
이동시켜야 합니다.
파일 위치 지시자란?
FILE 구조체의 멤버 중에는 파일의 위치 정보를 저장하고 있는데,
이 멤버의 값은 fgets,fputs와 같은 함수가 호출될 때마다 갱신됩니다.
예를 들어 fgets 함수 호출의 경우
이 지시자가 가리키는 위치를 시작으로 문자열을 읽어 들입니다.
파일 위치 지시자의 이동은 fseek함수를 사용하며 다음과 같습니다.
fseek(fp,2,SEEK_SET); //파일 맨 처음에서 오른쪽으로 2번째로 이동
fseek(fp,2,SEEK_CUR); //현재 위치에서부터 오른쪽으로 2번째로 이동
fseek(fp,-2,SEEK_END); //파일 맨 끝에서 왼쪽으로 2번째로 이동
SEEK_SET(0), SEEK_CUR(1), SEEK_END(2)
//SEEK_END에서 말하는 파일의 끝은 EOF를 의미합니다
그리고 파일 위치 지시자의 현재 위치를 반환할 때는 ftell함수를 사용합니다.
long fpos=ftell(fp);
//ftell의 반환형은 long입니다.