http://kid1412org.tistory.com/21
파일의 개방(Open)과 종결(Close)
파일의 개방(open)
- 파일을 개방한다는 의미는 파일과 데이터를 주고 받을 수 있는 스트림을 생성한다는 뜻
fopen : #include<stdio.h> FILE* fopen(const char* filename, const char* mode);이 함수 원형이다.
- filename은 open 시킬 파일의 경로이다.
- mode는 oper시킬 파일을 어떤 식으로 열지에 대한 것이다.
파일 접근 모드
- r : 파일을 읽기 위해서 개방한다. only read
- w : 데이트를 쓰기 위해서 개방한다. only write, 지정해준 파일이 없을 경우 알아서 생성한다.
- a : 지정해준 파일이 존재하면 데이터를 지우지 않고 그 파일의 끝에서부터 데이터를 추가한다.
- r+ : 읽고 쓰기 위해 개방한다. 파일이 존재 안할경우 생성하고, 존재할 경우 파일을 지우기는 않고 덮어쓴다.
- w+ : r+ 모드와 달리 파일이 존재하면 파일 자체를 지워버리고 기록한다.
- a+ : r+ 모드와 달리 파일이 존재파면 파일의 끝에서부터 데이트를 추가한다.
데이터 입.출력 모드
- t : 텍스트모드
- b : 2진 모드
- CR : 특수문자 'r'로 표현되며, 커서의 위치를 그 줄 매 앞으로 이동하라는 의미이다.
int main()
{
printf("ABCDEFGr");
printf("1234567 ");
return 0;
}
위의 소스에서 보면 r를 써서 ABCDEFG를 찍고 나서 커서를 맨 앞으로 옮기고 그다음에 1234567를 찍기 때문에 ABCDEFG가 사라진다.
LF : 특수문자 'n'로 표현되며 커서의 위치를 그 다음 줄로 이동하라는 의미이다. 단, 커서의 위치까지 맨 앞으로 이동하라는 뜻은 아니다
#include <stdio.h>
int main()
{
printf("ABCDEFGn");
printf("1234567 ");
return 0;
}
위와 같은 소스의 결과를 보면 n에 대한 그림처럼 나오지 않고 rn이 합쳐진 결과값이 나온다.
- 이유는 아래쪽에서 설명하겠다.
텍스트 모드와 2진 모드
- 2진 모드 : 프로그램상에서 파일로 데이터를 쓰거나 읽어 들이는 경우에 아무런 데이터의 변환도 일으키지 않는 데이터 입출력모드
- 텍스트 모드 : 프로그램상에서 파일로 데이터를 쓰거나 읽어들이는 경우에 데이터 변환이 일어나는 입출력 모드
- 텍스트 모드일때 C프로그램에서 n는 rn으로 변형되서 인식을 한다.
- 따라서 문자열과 같은 텍스트 기반의 데이터는 텍스트 모드로
- 데이터의 변환이 발생하면 안되는 경우(영상 데이터 입출력 같은)에는 2진 모드로 데이터를 입출력해야한다.
파일 개방 모드의 완성
- 여기서 말하고 싶은건 위에서 파일접근모드와 데이터 입.출력모드의 구성을 조합해서 쓸수 있다는 내용이다.
FILE 구조체의 포인터(파일 포인터)
- 지정한 파일과의 데이터 입.출력을 위해 스트림을 생성하는 함수이다.
리턴 값은 무엇인가?
- FILE이라는 구조체 변수의 포인터이다.
- FILE 구조체 변수는 개방한 파일에 대한 여러가지 정보를 지니는 변수이다.
무슨 목적으로 사용하게 되는가?
- 데이터를 입.출력할때 : FILE 구조체 변수를 참조하면 데이터를 입출력할 파일이 무엇인지 알 수 있다.
- 위치 정보를 참조 할 때 : FILE 구조체 변수는 파일 내의 위치 정보를 지니고 있다. 이를 참조하면 해당 파일의 어느 위치까지 데이터를 입력 혹은 출력했는지 알 수 있다.
- 파일의 끝을 확인 할 때 : FILE 구조체 변수를 참조하면 파일의 끝까지 데이터를 읽어 들였는지에 대한 정보를 알 수 있다.
파일의 종결(close)
- fclose : #include<stdio.h> int fclose(FILE* stream)이 함수원형이며 해당 스트림을 소멸 하는게 역할이다.
int main()
{
int state;
FILE* file = fopen("Test.txt","wt");
if(file==NULL)
{
printf("file open errorn");
return 1;
}
state = fclose(file);
if (state!=0)
{
printf("file close error!n");
return 1;
}
return 0;
}
- 위에서 오픈모드를 wt로 하였기 때문에 Test.txt라는 이름의 파일이 존재하지 않으면 현재 디렉토리에 파일이 생성될 것이다.
II. 파일 입.출력 함수
기능 / 스트림 | 키보드/모니터 | 선택(키보드/모니터,파일) |
---|---|---|
문자 출력 | int putchar(int c) | int fputc(int c,FILE* stream) |
문자 입력 | int getchar(void) | int fgetc(FILE* stream) |
문자열 출력 | int puts(cpmst char* s) | int fputs(const char*s, FILE* stream) |
문자열 입력 | char* gets(char* s) | char* fgets(char* s,int n,FILE* stream) |
형식 지정 출력 | int printf(const* format,...) | int fprintf(FILE* stream,const char* format,...) |
형식 지정 입력 | int scanf(const char* format,...) | int fscanf(FILE* stream, const char* format,...) |
- fputs 함수를 이용한 파일 출력
int main()
{
int state;
FILE* file = fopen("Test.txt","wt");
if (file==NULL)
{
printf("file open error!n");
return 1;
}
puts("Dont's Worry!");
fputs("Dont's Worry!n",stdout);
fputs("Dont's Worry!n",file);
state = fclose(file);
if (state!=0)
{
printf("file open error!n");
return 1;
}
return 0;
}
- puts로 문자열을 모니터에 찍고, fputs로 스트림이 stdout이니까 모니터에 출력하고 그다음 fputs에서 스트림이 file이므로 Test.txt 파일에 저장한다.
- fgets 함수를 이용한 파일 입력
int main()
{
int state;
char buf[30];
FILE* file = fopen("Test.txt","rt");
if (file==NULL)
{
printf("file open error!n");
return 1;
}
fputs("데이터 입력:",stdout);
fgets(buf, sizeof(buf),stdin);
puts(buf);
fgets(buf,sizeof(buf),file);
puts(buf);
state = fclose(file);
if (state!=0)
{
printf("file open error!n");
return 1;
}
return 0;
}
fgets로 먼저 키보드에서 받아드린 값을 puts로 모니터상에 출력을 하고 두번째 fgets는 file로 부터 문자열을 읽어와서 puts로 출력을 한다.(Test.txt 파일안에 글이 있다면 화면에 찍힌다.)
- 위 소스에서 문제점은 만약 배열의 크기를 넘어 가면 어떻게 할것인가 이다.
- 따라서 파일의 끝에 도달했을음 확인할 방법을 찾으면 된다.
- fprintf와 fscanf 함수를 이용한 파일 입.출력
int main()
{
int state;
int i,j;
int a=0,b=0,c=0;
char c1=0,c2=0;
FILE* file = fopen("Test.txt","wt");
if (file==NULL)
{
printf("file open error!n");
return 1;
}
for(i = 2;i<10;i++)
for(j=1;j<10;j++)
fprintf(file,"%d * %d = %dn",i,j,i*j);
state = fclose(file);
if (state !=0)
{
printf("file close error!n");
return 1;
}
file = fopen("Test.txt","rt");
if (file == NULL)
{
printf("file open error!n");
return 1;
}
for(i=2;i<10;i++)
for (j=1;j<10;j++)
{
fscanf(file,"%d %c %d %c %d",&a,&c1,&b,&c2,&c);
printf("%d %c %d %c %dn",a,c1,b,c2,c);
}
state = fclose(file);
if(state!=0)
{
printf("file close error!n");
return 1;
}
return 0;
}
파일 입.출력 함수와 FILE 구조체 변수
- 파일 위치 지시자 : 파일을 어디까지 읽었는지, 어디까지 썼는지 그 위치를 기억하고 있다는 뜻 이러한 정보를 기억하고 있는 변수
III. 파일의 끝을 확인합시다.
- 리턴 값을 참조하는 방법
함수 | 파일의 끝에서 리턴 되는 값 |
---|---|
fgetc | EOF(-1) |
fgets | NULL 포인터(0) |
fscanf | EOF(-1) |
int main()
{
int state;
char* pState;
char str[20];
FILE* file = fopen("Test.txt","rt");
if (file==NULL)
{
printf("file open error!n");
return 1;
}
while (1)
{
pState = fgets(str,sizeof(str),file);
if (pState == NULL)
break;
fputs(str,stdout);
}
state = fclose(file);
if (state!=0)
{
printf("file close error!n");
return 1;
}
return 0;
}
while 문에서 파일의 끝이 나올때 까지 반복하면서 데이터를 읽어 들인다.(참고로 이전에 만들어진 구구단 test.txt를 가지고 하는 것이다.)
int main()
{
int state;
char ch;
FILE* file = fopen("Test.txt","wb");
if (file==NULL)
{
printf("file open error!n");
return 1;
}
fputc('1',file);
fputc((char)255,file);
fputc('2',file);
state=fclose(file);
if (state!=0)
{
printf("file close error!n");
return 1;
}
file = fopen("Test.txt","rb");
if (file==NULL)
{
printf("file open error!n");
return 1;
}
while (1)
{
ch = fgetc(file);
if (ch == -1)
break;
printf("data : %cn",ch);
}
state = fclose(file);
if (state!=0)
{
printf("file close error!n");
return 1;
}
return 0;
}
결과값을 찍어 보자
- 위에서 1, (char)255, 2 를 저장하였음에도 불구하고 1만 출력되는 것을 볼 수 있다.
- (char)255는 10진수로 -1이다. 그런데 while문에서 -1이 file 안에 있다면 반복문을 빠져 나오는 것인데 (char)255를 -1으로 인식하여 종료가 되는 것이다.
int main()
{
int state;
int ch;
FILE* file = fopen("Test.txt","wb");
if (file==NULL)
{
printf("file open error!n");
return 1;
}
fputc('1',file);
fputc((char)255,file);
fputc('2',file);
state=fclose(file);
if (state!=0)
{
printf("file close error!n");
return 1;
}
file = fopen("Test.txt","rb");
if (file==NULL)
{
printf("file open error!n");
return 1;
}
while (1)
{
ch = fgetc(file);
if (ch == -1)
break;
printf("data : %cn",ch);
}
state = fclose(file);
if (state!=0)
{
printf("file close error!n");
return 1;
}
return 0;
}
위 소스는 이전 소스에서 char ch를 int ch로 바뀐 점이다.
- 여기에 대한 설명은 아직 제대로 이해를 못해서 책을 봐주세요 ;;;
feof 함수를 사용하는 방법
- feof : #include<stdio.h> int feof(FILE* stream)이 함수 원형이며 호출시 전달되는 파일 포인터가 가리키는 파일이 끝에 도달한 경우 0이 아닌 값을 리턴한다.
int main()
{
int state;
char ch;
FILE* file = fopen("Test.txt","wb");
if (file==NULL)
{
printf("file open error!n");
return 1;
}
fputc('1',file);
fputc((char)255,file);
fputc('2',file);
state=fclose(file);
if (state!=0)
{
printf("file close error!n");
return 1;
}
file = fopen("Test.txt","rb");
if (file==NULL)
{
printf("file open error!n");
return 1;
}
while (1)
{
ch = fgetc(file);
if (feof(file)!=0)
break;
printf("data : %cn",ch);
}
state = fclose(file);
if (state!=0)
{
printf("file close error!n");
return 1;
}
return 0;
}
책에서 나온 실행 결과는 잘못된 것이고 p.558에 있는 실행결과처럼 나와야 한다.
이전 소스에서는 while문 안에 if(ch == -1) 일때 반복문을 빠져 나오게 하였지만 좋지 못한 결과가 나오기도 했다.
- 그러나 feof를 써서 0이 아닌 값 즉 파일의 끝에 도달하면 0이 아닌 값을 리턴 할때 반복문을 빠져 나오게 한다.
IV. Random Access 파일 입.출력
fseek : #include<stdio.h> int fseek(FILE* stream, long offset, int wherefrom)이 함수원형
- 파일 위치 지시자를 원하는 위치에 놓을 수 있다. stream이 가리키는 파일의 파일 위치 지시자를 시작 위치 wherefrom에서부터 offset 만큼 이동한다.
만약에 wherefrom이 | 파일 위치 지시자를 offset 만큼 이동하기 전에 |
---|---|
SEEK_SET(0)이라면 | 파일의 맨 앞으로 이동한다. |
SEEK_CUR(1)이라면 | 이동하지 않는다. |
SEEK_END(2)이라면 | 파일의 끝으로 이동한다. |
int main()
{
char buf[10];
FILE* file = fopen("Test.txt","wt");
fputs("1234abcd56789",file);
fclose(file);
file = fopen("Test.txt","rt");
fgets(buf,7,file);
printf("%sn",buf);
fseek(file, 2, SEEK_CUR);
printf("%cn",fgetc(file));
fseek(file,-2,SEEK_CUR);
printf("%cn",fgetc(file));
fseek(file,2,SEEK_SET);
printf("%cn",fgetc(file));
fseek(file,-2,SEEK_END);
printf("%cn",fgetc(file));
fclose(file);
return 0;
}