chapter 21
파일 입출력
- fopen : 파일과 스트림을 형성하게 하는 함수.(type은 FILE 구조체 포인터 FILE*)
#include <stdio.h>
FILE* fopen(const char* filename, const char* mode);
// 성공시 해당 파일의 FILE 구조체 변수의 주소값, 실패 시 NULL포인터 반환.
- fclose: 스트림의 소멸을 요청하는 함수
#include <stdio.h>
int close(FILE* stream);
파일의 개방모드
모드 | 스트림의 성격 | 파일이 없으면? |
---|---|---|
r | 읽기가능 | 에러 |
w | 쓰기가능 | 생성 |
a | 파일의 끝에 덧붙여 쓰기 가능 | 생성 |
r+ | 읽기/쓰기 가능 | 에러 |
w+ | 읽기/쓰기 가능 | 생성 |
a+ | 읽기/덧붙여 쓰기 가능 | 생성 |
=> r모드는 읽기모드라 파일이 보존된채로 그대로 읽을수 있지만,
w 모드는 쓰기모드라 파일이 다시 초기화된후(백지) 쓰기가 된다는 것을 명심하자.
r+ 와 w+ 도 마찬가지이므로 보존된 채로 쓰고 읽고싶다면 r+을,
초기화시키고 읽고 쓰고 싶다면 w+을 쓰도록 한다.
- 텍스트 파일과 바이너리 파일
사람이 인식할 수 있는 문자를 담고 있는 파일을 가리켜 ‘텍스트 파일’이라 하고,
컴퓨터가 인식할 수 있는 데이터를 담고 있는 파일을 가리켜 ‘바이너리 파일’ 이라 한다.
- 텍스트 모드와 바이너리 모드
- 텍스트 형태의 파일 형식은 개방모드로 rt,wt,at,r+t,w+t,a+t(텍스트 모드)를 사용하면되고,
바이너리 형태의 파일 형식은 개방모드로 rb,wb,r+b,w+b,a+b(바이너리 모드)를 사용하면 된다.
덧붙여 각 os마다 개행문자의 형식이 다른데 (unix는 ‘\n’, windows는 ‘\r\n’, mac은 ‘\r’),
텍스트 모드를 사용하면 개행문자를 각 os에 맞게 변환해준다.
그리고 ‘r’이나 ‘b’를 사용하지않고 개방모드를 한다면 자연히 텍스트 모드로 개방된다.
따라서 바이너리 파일은 변환되면 안되기에 개방모드에 b를 반드시 붙여야 한다.
- feof: 파일을 끝까지 복사하는 함수
#include <stdio.h> int feof(FILE* stream); // 파일의 끝에 도달한 경우 0이 아닌 값 반환.
- 바이너리 데이터의 입출력: fread, fwrite
```c
include
size_t fread(void * buffer, size_t size, size_t count, FILE * stream); // 성공시 전달인자 count, 실패 또는 파일의 끝 도달 시 count보다 작은 값 반환
include
size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream); // 성공시 전달인자 count, 실패 시 count보다 작은 값 반환
* 서식에 따른 데이터 입출력: fprintf, fscanf
```c
## include <stdio.h>
int main(void){
char name[10]="kimdo";
char sex='M';
int age=27;
char name2[10];
char sex2;
int age2;
FILE * fp = fopen("info.txt", "wt");
fprintf(fp,"%s %c %d", name, sex, age);
fclose(fp);
fp = fopen("info.txt", "rt");
fscanf(fp,"%s %c %d", name2, &sex2, &age2);
printf("%s %c %d\n", name2,sex2,age2);
fclose(fp);
return 0;
}
- 구조체 변수의 입출력
typedef struct{ char name[20]; char sex; int age; }
=> 위처럼 텍스트 데이터와 바이너리 데이터를 모두 담고 있는 구조체는 어떤식으로 입출력하면 좋을까
아무래도 멤버 각각을 따로 입출력하는 것보단 구조체를 한꺼번에 입출력 하는게 간단한데,
구조체 변수를 하나의 바이너리 데이터로 인식하고 처리하면 된다.
=> 바이너리 데이터이니 fwrite, fread 사용
```cinclude
typedef struct{
char name[20]; char sex; int age; }Friend;
int main(void){
FILE* fp; Friend f1; Friend f2;
//file write fp = fopen(“friend.bin”,”wb”); printf(“친구 정보 입력(name, sex, age)\n”); scanf(“%s %c %d” , f1.name, &f1.sex, &f1.age); fwrite((void*)&f1, sizeof(f1),1, fp);
fclose(fp); //스트림 삭제
//file read fp = fopen(“friend.bin”,”rb”); fread((void*)&f2, sizeof(f2),1, fp); printf(“%s %c %d \n”, f2.name, f2.sex, f2.age);
fclose(fp);
return 0; }
* 파일 위치 지시자의 이동: fseek
```c
## include <stdio.h>
int fseek(FILE* stream, long offset, int wherefrom);
// 성공 시 0, 실패 시 0이 아닌 값을 반환
매개변수 wherefrom | 파일 위치 지시자 |
---|---|
SEEK_SET | 파일 맨 앞에서부터 이동을 시작 |
SEEK_CUR | 현재 위치에서부터 이동을 시작 |
SEEK_SET | 파일 맨 끝에서부터 이동을 시작 |
=> 파일을 동시에 읽고 쓰고 할때, 위치를 초기화하거나 옮겨야하는데 이때 많이 사용된다. 따라서 반드시 알고 가자
## include <stdio.h>
## include <stdlib.h>
## define true 1
int main(void){
FILE * fp = fopen("simple.txt","w+");
char * str1= (char*)malloc(sizeof(char));
char * str2= (char*)malloc(sizeof(char));
int opt;
int ch;
while(true){
printf("select option (1.read 2.write 3.quit)\n");
printf(" : ");
scanf("%d", &opt);
if (opt ==1){
fseek(fp,0,SEEK_SET); // 파일위치를 처음으로 초기화. 그래야 처음부터 읽을 수 있다.
while((ch=fgetc(fp))!=EOF)
printf("%c",ch);
printf("\n");
}
else if(opt ==2){
printf("write: ");
scanf("%s",str2);
fputs(str2,fp);
}
else
break;
}
fclose(fp);
return 0;
}
- ftell: 현재 파일 위치 지시자의 위치 알아내기
## include <stdio.h> long ftell(FILE * stream);